From 0c88c66071da4053ad27bd3f87a6431f5760e21e Mon Sep 17 00:00:00 2001 From: Jeremy Faller Date: Mon, 24 Aug 2020 14:12:59 -0400 Subject: [PATCH] Use local time zone when issuing a code. Rather than requiring the user to use UTC when requesting a code, use the client's local timezone. Fixes #63 --- cmd/get-code/main.go | 13 ++--- cmd/server/assets/home.html | 15 ++---- e2e-test | Bin 0 -> 8093292 bytes pkg/api/api.go | 5 +- pkg/clients/apis.go | 3 +- pkg/controller/issueapi/issue.go | 57 ++++++++++++++++++--- pkg/controller/issueapi/issue_test.go | 68 ++++++++++++++++++++++++++ pkg/controller/jwks/jwks.go | 43 ++++++++++++++++ tools/e2e-test/main.go | 2 +- 9 files changed, 178 insertions(+), 28 deletions(-) create mode 100755 e2e-test create mode 100644 pkg/controller/issueapi/issue_test.go create mode 100644 pkg/controller/jwks/jwks.go diff --git a/cmd/get-code/main.go b/cmd/get-code/main.go index 622635796..ec7620d17 100644 --- a/cmd/get-code/main.go +++ b/cmd/get-code/main.go @@ -31,11 +31,12 @@ import ( ) var ( - testFlag = flag.String("type", "", "diagnosis test type: confirmed, likely, negative") - onsetFlag = flag.String("onset", "", "Symptom onset date, YYYY-MM-DD format") - apikeyFlag = flag.String("apikey", "", "API Key to use") - addrFlag = flag.String("addr", "http://localhost:8080", "protocol, address and port on which to make the API call") - timeoutFlag = flag.Duration("timeout", 5*time.Second, "request time out duration in the format: 0h0m0s") + testFlag = flag.String("type", "", "diagnosis test type: confirmed, likely, negative") + onsetFlag = flag.String("onset", "", "Symptom onset date, YYYY-MM-DD format") + tzOffsetFlag = flag.Int("tzOffset", 0, "timezone adjustment (minutes) from UTC for request") + apikeyFlag = flag.String("apikey", "", "API Key to use") + addrFlag = flag.String("addr", "http://localhost:8080", "protocol, address and port on which to make the API call") + timeoutFlag = flag.Duration("timeout", 5*time.Second, "request time out duration in the format: 0h0m0s") ) func main() { @@ -58,7 +59,7 @@ func main() { func realMain(ctx context.Context) error { logger := logging.FromContext(ctx) - request, response, err := clients.IssueCode(ctx, *addrFlag, *apikeyFlag, *testFlag, *onsetFlag, *timeoutFlag) + request, response, err := clients.IssueCode(ctx, *addrFlag, *apikeyFlag, *testFlag, *onsetFlag, *tzOffsetFlag, *timeoutFlag) logger.Infow("sent request", "request", request) if err != nil { return fmt.Errorf("failed to get token: %w", err) diff --git a/cmd/server/assets/home.html b/cmd/server/assets/home.html index 15a0a1253..85a0ddd3c 100644 --- a/cmd/server/assets/home.html +++ b/cmd/server/assets/home.html @@ -102,25 +102,15 @@

Create verification code

- + - - Recommended. - This is the UTC date when the test was performed. - Click here to use today's UTC date. -
- +
- - Recommended. - This is the UTC date when symptoms began. It cannot be more than {{.maxSymptomDays}} days ago. - Click here to use today's UTC date. -
@@ -270,6 +260,7 @@

Create verification code

$($form.serializeArray()).each(function(i, obj) { data[obj.name] = obj.value }); + data.tzOffset = new Date().getTimezoneOffset(); getCode(data); }); diff --git a/e2e-test b/e2e-test new file mode 100755 index 0000000000000000000000000000000000000000..c216937dfbbd0ceb844c46924b834c47522a9726 GIT binary patch literal 8093292 zcmeFa3w%_?*+0I4EJPumML;5=EH!HIMp97|A-aJ?&*Da-B1RC2C=nC{!!8K|x?y*L z^Z&g0 ze6l-dF3&vk%yXM(=FDzB{KfY@ZMLlLHk+**{&VqfJDwlv?__-G_@6YXs_cr2@fFuz zZ5AZIvXaT8rwFG39ZZ@uwxW7$T0PZ%*0{7xoB0gfY(-2jT z=QMaGn8eqlNz=TyOg=ii<&zY=hF+=(o__$|?K3fAz*O}!@yokY!Lty+vz6@fd(x!a zXU@8H`dt>lOn6Qcp2Idkw#V}^@gv_ANWLpC8(Wsr<*adX9;QBQa+b+&%ZFymN|Xow zC+FeznUf~_rcJ+X+Fi9XIj>#AbIR8E06YcB%1Hm7H0dtzh+>sl-nvfkoF;yIhy?!d zEag)@DZJ{f2YdtGOu$L7awq(}YP`$qO@Q8U$E4e&NeNK0mrQue<2OqB?SDZbf#)B9 zH+lB#GmZfXPxst5WwP(~Nw-X%TsLJ7=e0|C11zW}ycA%TW{_Ev zCYkUcvQv3;@i8ch;k~NzAJJ3c<6^yd?#cOlIJx zhI{*MlPAr-wQgD_y!w-BC7>UhQ0kvC6-5$i20U}TO3XUp_nZl@D6EXsbN?>9=`(L- zmzntOdTN%$@8&ZV{dN`2NMfc^UE^1G%U!omncWFq@rF4PUXL&3m#w%umFp$IGTzFnWktE$vW+I+O+Vk%Kvh23*m@?vB_+jXBYpGmFMHLFw`Jp>f8_a9_@^#98~^`r z|1IC#LlNc&5FwE`9vjB}bEnPr{KR@&lQY{!vsA@={0(-hf70PcNYBUj(f;<_Sa18b zi^3C-=fr<+{15ZZt{XOe+T>xk&7FQ5p83c8V*E>7m|^}U>Z1O2b7y;}%s7A4`Diz7 zvZ}y#HTdt;PE{V}nKrrZmb$saE~gmQ&#b$1_OR=w-0G{F=AC=K6iwz08#kqH_OzLI z%^p^kC{^GkUQ_=w_@igmO}Tug?=C2I!0fu0^g3o=|NHg76!>2X{4WLmmjeI)qd0vii>W%rmpI$hWa~7##}S(yfI^Lsk`#L@;hhV=`EW+ zcE%M~Ouup1g_Ca_TQup);=88ZF(0C9yjyRWdrQfT z^KSpq@y?ESkM?)HZv3t6hO%*GW3SVVBjSZ;d)VB@dNJkf%WSQZ+Io0|9-f_}hp%(! z;VbjRH7F@FTE%F5mxrBV9$I*Y?k_jycXyT>dnT0KRCaUOq=_xsU_aXvz8=18Vr($# zYlG!8`@61+-Ce4>3y%;zQ0xZSa}_ubz~$(HbvY9hv|4R&P@-eutJ;768;NcvjxP*V zIDU*`3%3+tskBIk_xl7qF%K|^&=U$qCPH1~b62u`nc05A54V@}8G!mJ^eMZZGt#*4 zF^rm&>IX2o5vu9v=uv#4lTG236Jr{EaGXrG8JEX*nZzcqLrr`9~T`Emk^v$v0Oc!tDYW1t!c6r zN2#l3HHnNWf{R@En-5BDdSv3W6-9rIpAD8M2W`R&o)x>#0?5dzOHk}K{=ypWj&<(9 zcipw%Nx(;Mt#}ql+eU{+KBF6d5pSY;sL8imwtbatjgX67hMMkuv7!iwPgxZoZNhJ@ zXk%O5Xw@UWHr;3uVYUb_Xwx~~vp_mA0Xd%VlvVDIR?mnx2ucgyD#x(kS (n8X&L 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