From 02f3c1cb19b18f8fbcef2d172c6d3e23fc5b2781 Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+WeebDataHoarder@users.noreply.github.com> Date: Sun, 6 Apr 2025 12:51:27 +0200 Subject: [PATCH] Rearranged wasm challenge utils --- cmd/go-away/main.go | 9 ++- cmd/test-wasm-runtime/main.go | 21 ++--- .../js-pow-sha256/runtime/runtime.go | 20 ++--- .../js-pow-sha256/runtime/runtime.wasm | Bin 234047 -> 234056 bytes lib/challenge.go | 17 ++-- .../{ => wasm/interface}/interface.go | 2 +- .../wasm/interface/interface_generic.go | 10 +++ .../interface/interface_tinygo.go} | 2 +- .../{utils_generic.go => wasm/runner.go} | 75 +----------------- lib/challenge/wasm/utils.go | 72 +++++++++++++++++ lib/http.go | 20 +++-- lib/state.go | 26 +++--- 12 files changed, 149 insertions(+), 125 deletions(-) rename lib/challenge/{ => wasm/interface}/interface.go (99%) create mode 100644 lib/challenge/wasm/interface/interface_generic.go rename lib/challenge/{utils_tinygo.go => wasm/interface/interface_tinygo.go} (99%) rename lib/challenge/{utils_generic.go => wasm/runner.go} (57%) create mode 100644 lib/challenge/wasm/utils.go diff --git a/cmd/go-away/main.go b/cmd/go-away/main.go index 261d866..fce74cb 100644 --- a/cmd/go-away/main.go +++ b/cmd/go-away/main.go @@ -82,7 +82,9 @@ func main() { socketMode := flag.String("socket-mode", "0770", "socket mode (permissions) for unix domain sockets.") slogLevel := flag.String("slog-level", "WARN", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)") - debug := flag.Bool("debug", false, "debug mode with logs and server timings") + debugMode := flag.Bool("debug", false, "debug mode with logs and server timings") + + clientIpHeader := flag.String("client-ip-header", "", "Client HTTP header to fetch their IP address from (X-Real-Ip, X-Client-Ip, X-Forwarded-For, Cf-Connecting-Ip, etc.)") policyFile := flag.String("policy", "", "path to policy YAML file") challengeTemplate := flag.String("challenge-template", "anubis", "name or path of the challenge template to use (anubis, forgejo)") @@ -110,7 +112,7 @@ func main() { leveler.Set(programLevel) h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ - AddSource: *debug, + AddSource: *debugMode, Level: leveler, }) slog.SetDefault(slog.New(h)) @@ -182,11 +184,12 @@ func main() { state, err := lib.NewState(p, lib.StateSettings{ Backends: createdBackends, - Debug: *debug, + Debug: *debugMode, PackageName: *packageName, ChallengeTemplate: *challengeTemplate, ChallengeTemplateTheme: *challengeTemplateTheme, PrivateKeySeed: seed, + ClientIpHeader: *clientIpHeader, }) if err != nil { diff --git a/cmd/test-wasm-runtime/main.go b/cmd/test-wasm-runtime/main.go index 805709d..f57ce9e 100644 --- a/cmd/test-wasm-runtime/main.go +++ b/cmd/test-wasm-runtime/main.go @@ -5,7 +5,8 @@ import ( "encoding/json" "flag" "fmt" - "git.gammaspectra.live/git/go-away/lib/challenge" + "git.gammaspectra.live/git/go-away/lib/challenge/wasm" + "git.gammaspectra.live/git/go-away/lib/challenge/wasm/interface" "github.com/tetratelabs/wazero/api" "os" "reflect" @@ -18,7 +19,7 @@ func main() { makeChallenge := flag.String("make-challenge", "", "Path to contents for MakeChallenge input") makeChallengeOutput := flag.String("make-challenge-out", "", "Path to contents for expected MakeChallenge output") verifyChallenge := flag.String("verify-challenge", "", "Path to contents for VerifyChallenge input") - verifyChallengeOutput := flag.Uint64("verify-challenge-out", uint64(challenge.VerifyChallengeOutputOK), "Path to contents for expected VerifyChallenge output") + verifyChallengeOutput := flag.Uint64("verify-challenge-out", uint64(_interface.VerifyChallengeOutputOK), "Path to contents for expected VerifyChallenge output") flag.Parse() @@ -32,7 +33,7 @@ func main() { panic(err) } - runner := challenge.NewRunner(true) + runner := wasm.NewRunner(true) defer runner.Close() err = runner.Compile("test", wasmData) @@ -44,7 +45,7 @@ func main() { if err != nil { panic(err) } - var makeIn challenge.MakeChallengeInput + var makeIn _interface.MakeChallengeInput err = json.Unmarshal(makeData, &makeIn) if err != nil { panic(err) @@ -54,7 +55,7 @@ func main() { if err != nil { panic(err) } - var makeOut challenge.MakeChallengeOutput + var makeOut _interface.MakeChallengeOutput err = json.Unmarshal(makeOutData, &makeOut) if err != nil { panic(err) @@ -64,7 +65,7 @@ func main() { if err != nil { panic(err) } - var verifyIn challenge.VerifyChallengeInput + var verifyIn _interface.VerifyChallengeInput err = json.Unmarshal(verifyData, &verifyIn) if err != nil { panic(err) @@ -75,7 +76,7 @@ func main() { } err = runner.Instantiate("test", func(ctx context.Context, mod api.Module) error { - out, err := challenge.MakeChallengeCall(ctx, mod, makeIn) + out, err := wasm.MakeChallengeCall(ctx, mod, makeIn) if err != nil { return err } @@ -90,13 +91,13 @@ func main() { } err = runner.Instantiate("test", func(ctx context.Context, mod api.Module) error { - out, err := challenge.VerifyChallengeCall(ctx, mod, verifyIn) + out, err := wasm.VerifyChallengeCall(ctx, mod, verifyIn) if err != nil { return err } - if out != challenge.VerifyChallengeOutput(*verifyChallengeOutput) { - return fmt.Errorf("verify output did not match expected output, got %d expected %d", out, challenge.VerifyChallengeOutput(*verifyChallengeOutput)) + if out != _interface.VerifyChallengeOutput(*verifyChallengeOutput) { + return fmt.Errorf("verify output did not match expected output, got %d expected %d", out, _interface.VerifyChallengeOutput(*verifyChallengeOutput)) } return nil }) diff --git a/embed/challenge/js-pow-sha256/runtime/runtime.go b/embed/challenge/js-pow-sha256/runtime/runtime.go index 82711ef..3931869 100644 --- a/embed/challenge/js-pow-sha256/runtime/runtime.go +++ b/embed/challenge/js-pow-sha256/runtime/runtime.go @@ -4,7 +4,7 @@ import ( "crypto/sha256" "crypto/subtle" "encoding/binary" - "git.gammaspectra.live/git/go-away/lib/challenge" + "git.gammaspectra.live/git/go-away/lib/challenge/wasm/interface" "git.gammaspectra.live/git/go-away/utils/inline" "math/bits" "strconv" @@ -31,8 +31,8 @@ func getChallenge(key []byte, params map[string]string) ([]byte, uint64) { } //go:wasmexport MakeChallenge -func MakeChallenge(in challenge.Allocation) (out challenge.Allocation) { - return challenge.MakeChallengeDecode(func(in challenge.MakeChallengeInput, out *challenge.MakeChallengeOutput) { +func MakeChallenge(in _interface.Allocation) (out _interface.Allocation) { + return _interface.MakeChallengeDecode(func(in _interface.MakeChallengeInput, out *_interface.MakeChallengeOutput) { c, difficulty := getChallenge(in.Key, in.Parameters) // create target @@ -63,24 +63,24 @@ func MakeChallenge(in challenge.Allocation) (out challenge.Allocation) { } //go:wasmexport VerifyChallenge -func VerifyChallenge(in challenge.Allocation) (out challenge.VerifyChallengeOutput) { - return challenge.VerifyChallengeDecode(func(in challenge.VerifyChallengeInput) challenge.VerifyChallengeOutput { +func VerifyChallenge(in _interface.Allocation) (out _interface.VerifyChallengeOutput) { + return _interface.VerifyChallengeDecode(func(in _interface.VerifyChallengeInput) _interface.VerifyChallengeOutput { c, difficulty := getChallenge(in.Key, in.Parameters) result := make([]byte, inline.DecodedLen(len(in.Result))) n, err := inline.Decode(result, in.Result) if err != nil { - return challenge.VerifyChallengeOutputError + return _interface.VerifyChallengeOutputError } result = result[:n] if len(result) < 8 { - return challenge.VerifyChallengeOutputError + return _interface.VerifyChallengeOutputError } // verify we used same challenge if subtle.ConstantTimeCompare(result[:len(result)-8], c) != 1 { - return challenge.VerifyChallengeOutputFailed + return _interface.VerifyChallengeOutputFailed } hash := sha256.Sum256(result) @@ -95,9 +95,9 @@ func VerifyChallenge(in challenge.Allocation) (out challenge.VerifyChallengeOutp } if leadingZeroesCount < int(difficulty) { - return challenge.VerifyChallengeOutputFailed + return _interface.VerifyChallengeOutputFailed } - return challenge.VerifyChallengeOutputOK + return _interface.VerifyChallengeOutputOK }, in) } diff --git a/embed/challenge/js-pow-sha256/runtime/runtime.wasm b/embed/challenge/js-pow-sha256/runtime/runtime.wasm index 2c0ca761f7e21a831d22948ca11d55cbc5c45976..cb5051891ed9a3b7954cef66b6d5fe4bc1382090 100644 GIT binary patch delta 23338 zcmeHvdt8;p_V+XM?7i7s-6$fW$lfRl-py-XdCUu@DP^b9G)2V=nis@N7Xv+B&@9mh z9Xff+iWHL)L*1m7l%{CZp;ANhl$n_&B^DMM>ib>uJR7#8o!{^MoPXZW=e5tnTC-+m z&CHrLYu2op-Ts`Q;+&xTS5?+Ue@$%>x$`qytfF*R6(`f2$=W`zWK6PlP(QD>?we;4 z9Zr;T*tCP6*_?_NmP{2Dh3X*b@Fc+zNxLVRS1{c2o!TwuGg}N-23q1YaMPR)i+1y- zIwwj2VG~v8#ua}Jh59c}$G;+_JEe2=Y4-ljN ze8_StZ&DtQ(=MDKZccumB~Fd&r^G2*+MqyAgNkx0^%YvUA?X0X&ZxTAP{iZcGEq$fMQ4fPE7dEZ9*j9sIFz~NpRQ|LhjX$I9 z)i;KQ+4Fw34uWvX^?jjD(#lVeOj&Z21rh*Oal)3YRVqCd^w#(f#NQRFu(8V@CfhHGQkowE)#$ ziee~+z-oHqB{{ugShKV{bU+H}o4*v2%)PCU>U5+=M&*B&QQGZ=WR(1$2#Lh;YYpGp z8LcBRqljllY0xyA8Vk8qH5C6SsFXgwafqpC)|$zytQEY`FZE6e7QjjHWtlc8A*{qi zVOYC{)(SNaXbGBYM0Q^pMCl*-3Y`%8jRSLv}ELwbNnRiVFSnW^JYH3}w1im&*09$X3Cp z*P3cD$xwr8Js~ohozv$>#*&J`Zp!JV*}m-}C9P{Cts6B@-7!1#pDf%F&*H7MM0KoO znk-VYf@>GWE#s(Jy+7Y(mBF@|swr)oQN(-M-cC2=B4f$jM${Vc^RlztV~(+SP4$%K zPUgb48s_-Ux?1jR{y&x}ts*X`^#9A$*xqipRhAcwi5jEA0K5~uJQ(^1GXiT=qy7mk zqyIwv9nC`YS6enp!% zt{5(jhZ9CjeMm!=Y_p?W+Ax#eBlh&ttCP~lsru81rR6b4EOVW*SCF-(b_};MLO$eN z!h-47W82lPm6~m~SL>+TP-nJo91dPum2{-*II89PE3I8k<+8*0FnEU_yyjTPqmZOT z%L~409mATEPkm;E;ZrjgyboT_-w`aG?=n5At((2ApK2S=m#olRw2O+)SZQ(D1L~uc z<^#z&e534`4DH#KmKa6prYKIkma$Ub(XOGM-Yy_|jVv8pxAZ!%(rc)6*LMF{Y3ZOS zy}-a<+fbA3ui28Fs*_jyA;Uta9_I4VUez14AH-hKN4FosUe$Bj4`n%eMfEU{*LR_hHclM?KObq>!rO~cdmQZs4~tP5CU90LkN~+ZPQ9iJ4Nnuc5S2H zuJ?23%ii9JR$05i)u#&!CbY~vw2vX)z1TzAE_7YS3CpFSe4b=ulrtu7t_by1Q3BIO4(_SY;(yd)E0{+bnuS7oA+ zk=P;=p++K4CK?)bcF07Ck+VxC8bI)1utz598;K&B2u30eS%+lG;jfiQ1gEyoB@*PX zosvkPzvhc_-^fIOzvhR;k22wJ@H_Ym4Z_b~3qnq%%<(lkv}6U1$ZjxLE)zb+Sl7tJ zSewz;buwi&66KePoyFiFWR7YING4!DXh<)~1T29CM{Dw@?M_P!4~Sx|)Jp1PZE71#YL$9l7-UnP07afQ5M*5XOcQr12!Iq3|5k3|HHjPr9UzBK`V7Iv*5F#eoUej z`ZvRt+KkcY)9*{MAMzCb?!FBe{L{mq$6x;uD<3^-W=1 z*fZv6JVO05CqtkI^ve(T)9)TVHtL7}SVJ!y9pxl1DiE$LL{6R*wkb7`W3P~VKG*i? z*G6{^$~bE^Z8OuBp4InHY^WzZ>d$uSV;*hH-qGhj+B@XZRjUg-zRQBm#jKm9A9}PE zZ0XOBE{&yZ8|~mhE{nD#%i>~akX*As8nx@)YfX)PyO^j@4SDDc?Wmfg0Xk`1fh z>hy`>ZC#u|j7ybcK}WHsq+|vL202x@poX!?*7uBcb$Dx)*)7fCBE@wiYq=g0l4x#| zS2A1odn`O{_bQ{0QtTx)%gS=L= z0Cm|BCB@Mg(l5L^*a``u6zBmiY_3{k9GI~97($U+=~b(_hcOyU@l~rSbw*<;@=6x! zKR(u^KDotS4Jlfl-e_Dawn^_dE~06^S8>$N^-6Bi7mjnWO8p<>nq!ZBZ(MZK{g-ZO zs?aN$uiqRO?mB$QP$Kl0oNuGm1~B=gLLi>jdya2A@SCev(-V=>KUvcz*FN>aLz0~~ z?ebNtlQnT#$-Mvz>0tP|nD(8%ZG3dZPggx^&$aJ7Ri)Tyls}E1+uftq)B)KAIs_Q~ z3M26C%d7~)#_;h_AEq@;j#8x^#8j-Rs2vHW zVo8NZK5}5!YUIPUU-V`ZI`QW#^!q0`BVMYhrqYycsHvuEDDnIR7c0^8Cq(+^{$WW* zZ&<2UqMw?O@KE~Kp5aPGsQSv&oK%DguOzr$@JgQX!lP>3HDjzfdiumpe>NZpqv9kI z*a+>@xhT*N2px<98v`j_XB!+C#?zcC1-JbAf2%wKnfh(P?%>_$@JSCm^55<=e5EK% z)*1caq_%J^FHb6Nd%{c382G=ul2AxvaY&`GV`9HcS_*AWp6vQ-ZQe3DhGpudlVh8{ zKF7A{i>5^fZeQo|vAMQQ-##ri==mB$%3(S6^V9O#`?^Rz%r5EUrmy2L_P{tBta*!)QBIjXOec7h=&Y z^R;?&w8MJTvJPPXz_NLW=@l<)5B&FK6Y6j9Ds9yQ=A+>Bre1CS?dlkLY`<##6NPW%_F?`?6B~?8;bHS`e@*-!~@xh^-qB!G4JCpc{8Mtxn#J z2LSkW<93h%ECAc}b9yK2)}dL8*fBjT>mhh*7qfJhUy!!`jLJ3^jDMkp1z_1f7cpnf zO^b9U{iHq1Gg47jO&J!5iyYhrMZMg>;%BzZam?xWS_FFJRozd6jK83$QTZdvrjouo~iuClY;rRRF)+x=-ykK+O zqbbBDAAe?l|}2YQGRLAi!#Y|cP9R;oN%Yg_fv+al{U-N0Z!Kr#Qh?Ap$Pf^7>~ zeZ#MHQuxf{2={q&N`1qR^(GhWelvj8H+=nD=*Qj)Wu`BCY5Q3I+$nu{{)XEW)PKu= z#WS}w2e0giU`O=*JNnci+K<#uOv7jm!^h@@+sG8{8{Bc-WOKCeAy9dhMo$__yvpAu zUVnePw+NJUZwt_xFpC$BC+1YKB*d z3;L4%oh8Gff<61kStXiZ(Cowg+`0)3AJ)$v-fdt7|12J1!@~UOllyTt>i4f5vg{`P z%D4cugauYVZ2`*_^JzTrIiI$MHQxBCuOAYdzif%b$6sFH>_oxtuTC&4$vLxN z?U|1m`#>LeHUhE6MQ0;qB#Tq5k(M{CN`=1dtm`kXk-j_IqBb;NrHrt|838O$NLhv~ z&6uGd;&(E#c$)|y1rO!rxBnQ%<>evyXmmB;xuBsd*eF<01%{Wxfle9DL5XHH(ND_# z^M%>wZy%_aS1fO2pwIERHO(m)e{mp#Cw$*`adorw@fRBx?E0=PYqN>2nYDmqC%iw$ z-G-R}E(3aX_{mDq-#26tvJ%QaMqvy`atj3!J33}dB`A3K!ZlvEK~G;cmyhveS*V*9 zbTjxT+0BQ4?pilX5B@2W5_THcaPk&@t_Iu>-OXvos2L)Z|LX$x}nq%bS> z%ISlCk*%bDRh_hY!U5S<=4S@ER0O#)%W%DpS?i}Dyh{%X(!Ye&04k@~kqX@5w_$d9FItSPGtv{Rq#q>8M_yX=utfiM^ltms-8-W%trz8s+N=! zdyCX)%KWqD9r*33zr4ScEa_f)!tcg)sma^(+h#; zpyEAx^FJD(a`!(*M*KzPN}+#qt-t<*EPMTrzijB7KBGDc4%?dQM7~<+zf?a_|D17( zV*>*jZ9F)T>x-^8MhC?8WL&=T8*O0!+TUoymuBgY-iTt=`ZG6L_*`B?QA?(Gs*bD^ zN;-bSYLnYdzDVU|Q zQunD~X6fXMD<)_zPNm}e{_Hxd5Z~Ry5D{}X8^97-O_>|r?e>jmfWh_seoy1y2pZU>>wUKaD*VS}QOv1y(K(isHU$tcj?c#<~W1 zgw>GL`JCvU%r1t#Tuw4uM8Pse`$KU&jbJ>m7u`LlGhLNRRpI_@CfmZiCd9{>kd?F9 z&YGyQd*B>)uj=^lq9=fW^Hj2SSiGFd`m$p2RVurS<%r;UtPN6q=CLjSDf8G(R_IQd z&z3Rvvb$;lt1!Z?#p0(Y*@_@f=j1b_9I@mnwnn-lneNc1S&2>JrS9*Suy<9*ix)jI z@*&Irnz)g{BHW)YXA#`7#VgMzS$oTkym8F&b`4pcyZ5*sU&RhE$J!dQjX1sFj$6%w znB&T=Loo@1+-V_yx~PNfgJuRYJYc?*k4VY%Zn+0TrXxjU?5p*#d5GXqpoxnHBX z63+-0?w*^)f*EFh*?RUo!4QGRV33t7n}xEIqDMBih;!~Iv)Nl5)Yuo9E3NpV)v=fb z1kl7e5ed~Ol5$SbOgbLanRE{N*&4c>Xj$GakH2PdT#=c@9VlK^Q`~+Fy-d+g8qNB+ zkG#m@RP@d7WlZ%+_mG!aOX}O~S7eV@yu!w&A)JE{Gx*5>4Cl5ki;cvJBmx zON1h65~2HbiBQZ>B6I^U5sE!Zgrc1ip)jaK;CLFyzHT0jqN*~FBCZmlxUNL1J%|iR zQ-`v|$2lzA&j^nreOkQxDx3WO@>rVGjwKuMHN=%wx@>6+@S_OKVPn$hQGgT&y%I1a zv+w|va>{21I6sS` z*Rf7Fiu*RR&TOApyqQJFDTIG2pO0A0=Ob40`G}QHn|K~#)v`=T3PEYo5Q3yK1WAVo zl2Q@eXTpspBt;}TX(mBZRf3gqCPLaw1X6E;#`6&{Hq*2sh;BR|vC1_=>1;7}3p?de zM5HNdN^dO8MP<~G6mwA-JSD|kR7R_kVlFCl4DCsZxu}e;ONzOuWSGe)vu`wpCG*Th zWeCLJ=*c3HNs76s453O2Nm(NFYDXfba-wI#v6a2;2fnyV!UgVDQL>dS2tO#N*`@M0 z%~S*FE@S@1*f-dS@SO-HD6m)Nc>?qt@sS96ZS$s-~vm zP>Nj|cR&CNV!^~x`n(qCQ~PbKA1e_vx3T9vUBU&Hr%S3l(xOYDdAD{+x_i_mc_u9p zX?gHtwz@awu?>tb749x?vA;8xEef}@_H4iSeml!xhs5lBc7Nc344Vrcj=Y*UBtFS! z;oVRC-DY0L$&0a1{w`mhE3$Jqh#L?N5Zz7l5&SpgFw>mBTjXT(SEu+i4#%WYaS zF>VhFB{tzG3-(>uE5x}A-;^Q7>|rfMIa+}Kcx?|R`m*S~mpx)#xzwh$HY#r4i;C|X zeQCT8_%~koSt_u|}USp(7t; zhG(dXB7UjXt%8wVWVdXTBSSkARKU3 zD29B7v`n*n6Bs z_XIj9CCax6^a;!Giq+}c#9v+vqPb0+Mu{*2jE!c|WaI!>Elng|Cc;m!PFMuPPO$Mt z#|x>Ch3Ml>vG)Xf+#GAWFW5xWJ6`_k~IukRq1g- zeKpV?J;@@`{ijaCL9Y~BPO?`2xunaV>`jp=|9+=fJyMtvU$TZW6q&uIHWXRrjf=%! zvWT{&&y%`183ba6wDGdR(BwZW*wHU>pez(Ir`ao*(4(i>T;mv;?F&>JHtk$Z?K6bs%G!M@SPP?DVsZs5 zX)W6;qZ(-MSWS&m!ZtCq_ls3KtRPV;5-+ia?m3rP95ZSao3#$s)G8vZ)Vo%ZtR*Ub zVJjfRg}<^0k1EYy26?T)C)&tQzONvzp^-^l|r+Xoi(lG6PEAYO1{xb zLM7{ZNA^L)zR_Y`t>J8yT#O)@1}@;;W;mzHcS&V++4E z_A0yAVc0hsb~+|;=`Z5%SFuTN5|^*C#QzL^gJbySU*8IVuOjX$Z8M%9? z+InN+{ex*{IvU$WPBr^TuAnm_^*VdozRi4)CEDL$OYW|yeUWASaO@5O#(}zy7=O6I z9yEHKZuYpEqg5%`D#GxizoTO8P1fN~-4y$7!p*1@hi|e7xwqVDVsD|Z59IB<>@|nI zULVh!vAp$Dco$Z=ek1RFr|ekKo^hJOo{aapbD@unLSHZ*g%x&<@gAtsne&-ajHO~T z=gnGGo`TG)7)8clRp5^p{y2gs(u2X2lOK^MF2YWMOMuD;*mo|5bI;(xKcaGSo#v~& zC)|h~DkpE^xXP#1`W6!{{0o-n?q%gIj3{HVdyXYkmHc zw&bQ0tf+-J96VBrf$PMw-NBH-#&NPXf2)ArRwvu{VTw0Js>!JG1ld z$cB6*Lvn5?pT)ix--hzu0M15SV;97PM(9_bXcor9L(5;FSB?+j+6Jc>xHCK+p7t>@ zJdDppkq^T7V$+((H|F;8!?8n??AQ-lW&huz;a<4y2< z!hJoG2Qii_0$jWk+ba4J$Q84V)T=Ij0fTrpia*oHY_r8c46{XT@7>Pk{1;DDxKT8} z57FnOXs%jOZ(3`P_s`<@*1R85-P`c=W?oJdgvF-&yQGnFAyf<9aUXBPOU=m_Z?xmX zp&eJ-k*>HS+VlOaMs?h*Bky1hg9^$u$}}h%W}&MSPSip;M)6&FH;g8&E8k!1qT^o2 zaM4F}!`x(v1Kp$+evb%3=5h*Zwr*5%=@H0W?TRf^G{8 zCBK_)HYv=2yHnaghe1XdZ8sh-7e5?jTKsajvKmB$0t$8M%Kf}sBz3h&Hynbk`1y2w z`uQ~dibHD41##~Kd{CoO+%n>&p>(}{G^D^&TdIpK5Ac80-1LZNM)EZd+^3j9YFu#Q zxt}}YLH-ak-V7r0hBt%mXa2^q{mU1521S4})qU|{-kk+vTF_gM57J>2ABvl$r$)gx zT^2h>@dTu-qh+e^Xr6-94kPvBXkOFyoJlbPd->z>ib>yals7o<#c*aAQO$rFpFVd|C& zv1=M{1+V+x(|BjQVNT(kg(dSRf;|JVI)m`w%LjvbHJPj4y_T0QUy5DRWv~0p;OA?H zipQhIP&?1!-_or?qd9z!g|EILKA*?0hUQ+ECv0CVAz!B*WwWvESewbEbHAAwTNTp?O)0W65 zxhjubrE6;sh83dYBK{9_`J+Yr1_EJUi;vQHJA&8Jcr-y*I*%mSKb(B=F+$jWa8^-G9;D?F3k*qy$DPj}&lvpkm%f}(fc z%5$;*;6VU(w%u=VKi0t9pYdJ*%NpwqTeOJS#{1oxVeH*v);8WT@cLR$%um&R6M5Ts z<9grYCq#W{)ob&I{6$#M@pO)hD+g3L!H|q@OjP6WZH6 zJQ}6sy9;_Xb;hhg5BwDu{aOKQ6$jwcBK>Ws$7&&R-sVr5GL9g_N*0d{D^}uElwD2l z&L#mlEyfk_7GYS9+UYem$59wn`Yn(J7ymFIr`<0W@bS#^>P0^5p;s^CFE(+6-F!D)Z76fXX#1pJOvr~$g>L)1+=qwO%rU+8A(zB|^(VZGJ9%~m z0X_xc>#74-0~Nw~kS}0UMD{`CWs2g1*d2;De8_)iyG7N9d>pGU9y!EEut!DiA$W?L z#DzorVeV@e+F{<3^$=4Jqr!Nx>9EW^a~NF8grk`EvTj7@#)yPs9vQLFmnj$6t-VVJ zje0jmtS;vFuopyWF|A2=RWbK%l6Lcm#h;}s+M1()n-uM3g2jrqo!~V^dk>JuZB(>R z2uV1gXkQW1qEgX*0-~mG$X2xLggN)UhyP2-N5EpH|Ey^LBV_@qDC$ldY_x~ipA zX5P%Z7A{|*Xg^SD=fiftexXyhD%w@I&v*Pxh_%aVrlgAUt30yZrd~|Rhb+S&JJp=& zT+nF7DQ&Q6J(YkV;4D9W#4dd7>Ue_+ls#e;vqO)u`vlorDI z2aj#g>8>6Vrlls#TF|K@_|m^Bagd7k5Y+@`ySr4wwS?-7yw1N%%fD&y-`tm!&EdzS z(h(jEoC6Zx062A#(xF~>W8fB(9s%46oXSOc;jMt%OnN)uKESC?7Z09>L@y*r<0<1F z;Jzk43^*KP$@n2Jd^~V}lRh1I0B~w#ffxRF;DIJR6L=7CYWyWHJP&wUJu_o35)Kpp z2zW4X>eOj3{3qb`P5MpX4S-W;>-*Q@(ZEAY`rW`A0;fR?_rfOv4>jm%$`eR5G7Dt_ zCyk)d<$B>oz#E(Nlfc7))2M&-!UF@C(!`|40B;JMBrw1W9}hgjq%Q*AOo9BV(2Gb! z0+N{ac;P33J5Bmk;4a`KvGBlJych5&lRg%BbKoS&bT9lh;4Mu0Vc^jwUj8>ES|UN> zt{+s3_W<6?q>lrRZBB}Qg%`dZIDQ!->1DuM1E(qB_1t!*KGwAUnRl)Je%H~LoA`?S z72NMEj8K0FbRC#sOiW5r;*1%yCiZkrn>jym#@2GZ2OP^zmii~*3YNnJT9fCzWd2aiJ#MG$+Q&MK7AWIpI zuiDJ>UhsaP(Sm=d&VnaCxO-HN;&Y@JM!*jE5zx?Pt%%bRlo2Ny`LI3b_wy$J0zXy^twoz|VolSAgaC&f{wf3-m~;0VkPo zjtLh@7|E0jAiYsA3y`(}Y8W@fN)9?PNeu6#wn@wbYMEQxAM{B%g(7h#Z47WS9aM$- z6AwC$)5;?m&<3z2*p`~X*V$}__+3MtserS^sZMH>B&tSiO8{x;v@YqRVH^XE;5R0` zWWwJ~c*BG?u%~iCCTwWJ2(#JQV)R|=tcD3lF2uAA0Q*URH1OWytGm>ZqxNAC2a)X& z{(_Xm*&a0*jbazfJm{mer!@OTiw$#MVYWi`6?;+&sZLLP2f;H;tm>>b(R$A_Sd)Pv zbL^=;4D0fY{>BfPlfJH1)Pnq0sNWv=rbui>V#dlrR7p4V$}pJ7TS=qaG5qvnU`Ez!R) z;T6#3xKJh)h9@7eP+ab&HW^OUr~^fSRHP7)25}6KRGw(XfK=w3nI?K-N=o7rpizD` z(!&8O7mC0>YBRC0yP6)H_k_WK`ay*@3f~^;0v`0FSkgnCV0{oH+9`hMp|)yW`lK-; z+D2%7QkPCIGHUHa9%*njpyesi^KP|SL>X{W;jpI+d1~3eS^eK>PK}_*yt~z&!A@k6 z+emt`8Z9jqMR%)_eFnhzknG6j(-yoB#q#mZzJM zqG?aHNtzwm;b1|kMJ!0MX*tq_<1L^PgRdz*>dk4eR+I_zCSw$GZN>fK9H0+ zNm0H}o%pvJ_Tht>h_}1i`D?0X8 zn^>2EZBvoZTWysV2mK}PBve|jWMkt&qgqbTNtjKMwkQuJ&X|`ZH;Si`rZWKT?=%tT z!0y;=^c3{30kgs5dqAq20NN?QO=caM7W&9K;V2j?3oS+F10d!DQY8eU`=}kPPlNAH z5!Xj;6Wt}v=q5Eu-6XO0294&vKOog|h|E6fl-MOmlD85S)l)8~LZpk#B6)zMRi^>Z z31?rmQ5t21gA|``v=9%RHXjl|0%)XV4+Bzqq6udMlF4}nkoK0PfF$IwNW3l%yduXU|JT zS?c&0v#b-i1s_TF80Ien@DkcMvyv&*fJDD;svhwtn>ZVgR0h3IlLd-FOg9KJL#{cb zX^5U-665<(F4rtabShT_Sd7n8E+4owyk0cQms18vgFOuxg3fN|kmH?3J7Qj{94?JE zUKTbCo@cZPppnMrVsxI-QYY>*M@tP@lmUsUiHh<8c#KDyI^o&UW+UB`*7;N*oABKt zdhzujwb2l2yTr`$7~8s%ru05@R*8*88Ja{pN(sJmNK>1qMciO@y5BJ92q}R@6}twj zQQ9P=smnE*I(**a6JV~NRG>@9+i2Q(X|3pw>04YtehKmyim-UKx%C*(d=VF~M#i2d zDmaowNlBVKBWYsljA^M!?T1dA31h8b53)!Lvs7fDxU~|+6GR?Rn+0uQ+xawJjj{#+ zUnr`;+t$<|yN0OE(pmsd$9D#!HJP_J44J{WE%GMS$xlgK@Zb}(laz8a+#7kPA(7$e z+}tPTPJ~*w$B1UmLdTB7%+NM=979Wh?h?$v26-G7YN<51YMS!2nK65@QJ@9P1Qk3Z zO&wDzWWh$tc#~1KS-yual{0)`g5>iahu6_VLayXUSBxuF62hmD^{i5@h(CpUjw@-6 zl^BU2ECToExH3o?W~Rr;`G;#H)7Y>iRF!;q_Qzq?$zeaP#LErgI2;!X#jb*RNmhMi=P@}QYVW}Wh>b0ye0Mk6%_ zd8B0?--PzFY7sD0ZDzwSDgD=X6di}EVS)DNm@)-*=}UG0ZK(QXNMOY)#`%rTaHZ}( z*61KbNpn`YXFKvYG`|Jdf=^?zI0tXqM) zvHRIiIp8P%9YLeSd=4Nr=4UqgHlPn;YM(%uW|_1*6{<#|PWG*<7SXKGzsq1odqF!e zA=pY-}#*n5p7_+5Dsbhh;NLZE5~mi-{Mr*j*IDfUbcF#Vfi3Quv^g+1R&e zgy@eUP2w#Eq?pCGfB|^=R|@I{@AE$U&+mDD_?)Tg zTXl7Hb#--h$I=aTcWkIz@S;v#&6o5R@f$vOwbHciy5=Rrn{I3lN+zWnTg)Hy)_wEr zOph0}JT7C)=Ps{i#H4dWP2)C5dICvMMA98d<`oWge6M#~{kbbiXagL{2B;ZckHfff zMSmzkL&gej&`oGz1}gQRmyLfVT6a$8np52Un-zcV@;HrLG~-%^=F`HwA>Pn*pA-EQ z7w&Q&)!irsd87)%XOffa<`yQ^9Z2-4Iiue1(Z|1Z8TeZ1T7P;1gEbB!kH=9I{Xuo2)%Q&6m@YKVg4ojC&RO+h64_f#)NxFE#lO>)s zHkos4|r5$&3`tEy3eBFsOIlGrt!V%%;L{c&08(j!u2pE ziXj*RRdW+0IkRI-v#dX0Kndx{p9)EpUROx97^#*~#kDfZy1tOCn*SRiu{h3D)2*4& zS`xFW1ZI>6&9iAx)YYn?g(X0x%(0E5Y(;ZcPu{T_!CQRkf23gHf(2i?!UZLSl^AbL zL`fBEv6o5$8K;$6dkO0;A*#PNf>m6tHn8x!)^7-wnKk*CGP0CYDSJCsv|t_Q!dfE7 zV!1K);T9G>pQb0U7wQiN7JT zY^ALU6D&=rFo(w{(mwOy_*SfCFr8|~dBU%|PFeBVC43k~MY)=p*KtSZ4P_j>B7))}RD8&+e(e^AVdfJMgowKY^( zJXH$wYFXqzR@Vw|^Z&I>c_9fkrT@Q7tsU-qyXE1+(Fvn<*nqba7e+$=U`b$*s?~pZ z%fvrXe^0Y0^Tn2pvastb}V2%w-%#}AZ z&pHh@!TnB~+hQATv0ZlBZM~}r=dI}Ra(6c z;ee`5kZbS`lojM=@gAu5D{C)jt?_Bt8sQmf%8WXVfa!1=%5+#2L)03#HrMO$h#elh z{H|GEO@I|;1LJ73}RBbIaSw;SXmx>#H!S*xPq)5HDkDr5ei}d z5*Ez7)T&+0TB+V?d$mruPVV&9jblN}s8YUkEnoGp`9f=7Q?=|cJ`COy3dgyX=RQbM zp@$2R=i*^Z#RXGlyJG?$> z86l9Ir%r+!lVM!QaU^M4H%;@pjj9~;&2|mV>~`UaS5)oD+O?lrTvPiB*Y4VG$zn$b zP3r{$VaCGh;xNON?$y2GVkin6eDEP(h_T9S(0(ATG)J``OsmWd?T656^K|>Jw8m`N zVKxp6c^w|1XUwRMy^(WA$LPqli<##-VctlCruym|ubXo^_MuX9TgSdsT6nf&o{JV1 zuIj#4M_#L5UGY1nR~vfXe5ThewBFp)t99qv$BpCGaRWktmuCsVk#4M5>}aQ{ea>wx zHQV)m7QDREJJqRL7y9~ip-4tc?Q;tY{$Sz6zAMPL{A;IC-*c}Pw$4G0tmZf$O-*pL z(2NkDZY)^n@CnnG++Gf!M4{%eZ^37DH!L!fg@wT_r-Sv1Tvg zvEJ{pczs%>oL1uSFHFv1QOHpxx-B4;fcfAdEmsLx0tZgl>{7eEjwBJDK&)IW!8PVS zV=%p7HtT=HJ#VSn)+)@9o3~;v-@W-Sblhxk%P`>MZ%M`PhqsKwZ_r7<*ife}+ z4qJlt)J-_BtSl;C;U%mnBmSYDn%k%_PYsK1c>R*t;S1cK2UvP}_}A{^fe|mc<74+$ zTNLKVJJ-424^%sU=O`*S|1zQn9Wj@UNQ^kPJYbc`I8s-T0v*3K<5JB@7QK4~{L zhmV}sYL7jdfKaccWC`>G^Ot-2nKzBPKjEwY*upFtmEdJBDgv%7M9!WRwkbVAV6RYn zzA!eM=SOv}TXn=~+h#HmBv&Ij0XhzR!Wp#cn&_ z{OGvI^tnhqbKLw3y~TwL3Bq6Mb-xzX{o(0pgKZ@}7B0c+~S zQZ<&Xa#*19v>^NC*8;m zWFd*}Rsw$zEo zQV^8PH-CDdN&SkeJJO6iv(cCvXocBtOkC6TLDkVZHz>KnoHNEp$IQQuX^uViy)lVR z-#B$uSNTE7_2!i^u|EGPONqcSJKxsu8o=bU3L&%1>^ZjWfW7COwkM*bzpJ`WVf-@) zk4pEtj3eiqUTWfXvU>p%%E1Wrk+I+0G&V8rf6fKeUKslWO_kVqls}K1)jgor%z$En z4*?cmF)Uuq5_=TH{u!93@ED$(JX5Cjy!|LLgwYgQ=0qemNsNX1kkK?fL05JVQ*r)O z%}6j6zg7!G4eY0&3JkdjrdK@l+`%d2yIE42T2+P#oz=*!q0f_aXeaOb`MZJyyP zC1A4lm^&x5g=_iCgwnPj1<4r$-w~9ALRyPMDTNyo`+eGcXmk2R-=Ayq%M+6*+uSp; zRnuhw5*RnA=L99Q&4!aE(OPrvq`4%`3zHJ#o<9{>o5GNRn$>;xnVdx*o9|9ejCeiB z;%qceO@5Z1Gv`i8jCg)kz{eKGbLJaUTGhS0GGJ5%ET{RylmdFwl<6PSx8|6ss|1Yw znW=>hilHgCQ3!zt?F}{FHQ%0=cy+#R<^M7*mfkhPAB=DCZg49Xmlm6SYv;SCdg~y6 z=7X8up!#k@Oic(iN^n#Y-f$$m5vb&t-Up=nPfw!a!l~0siTq}lnRk=F@R^yt$T=V9 zp!tQnA8PKX%RW%K?POp2s_^3Mm)%ye?B@`^!d*{p74&Uk*1V;9qxqL$w7t3^JW;p~ zaTtz=jd~9meluY~2avyW!ED6zN*A;T{`-P)^%n-!b{gRiqvF(slTi4@Lhxa>UNi!~ zPcGU;WoAlFr|7b0o$Q!-F$^7RTVxuJ3|OhL#MFA7VS`COlrJ zS9BBM0HNK48`%I3falF)W+&{{(W~duPIL9@yWy#wSZ&h!!mKsrIxQ_6yRL-;V8P$! zl6UnLhjJ!El|9R|QVC8&yDb8DIk*r?c)o!n)b3f}nA7j2I2@Jke`&CyI?ALC29`k9 znp+E>-S7aR!-{`AjNiJi#F^O}+hYK4Z1lm4-n%gtzZDxNpzMy9n}EFsUv3v#WsL}j z8uM?j#<`#WogJufmzlaLrdApHtdpNZd(2h&kK?!QD?_lNM!k|q1!nduvG{%Nl}XL^ ztaEv8HZ<((j#l~{Uno%B3$G%Z;2Uf(y|1>dMK#c)xK5AtY;JInZU~olgSqR~8^HE2 zulDG~K_@o*{9&`@pC|*ufgWN+P_DrSJv0E0m99?K#yWG|kiQ&I4wp zWLgz(F|DWHYI$=_rlqMm-$I7tWRLlEqi!A6RNb)pu!wV%uQs(Pt3p_R%@+dCsDBoM z0UOM?LL*p~lMCbA?<;0e_H5xa%+dM6rcHPSTD`t+cG_~s)x(Xh7bpu5 zdUH$1|5U}ZwGpi|leSLu?p)`>^pUSFJV>wOU0(wOnurhtF8A2k&o*D*Iwd@(3ioeS z4sZP?#=gSl+gj=Bpmor^R{Xe$aesM`uN_pm6(+F;0c9FKqVV4&hvZj{WA*kGEM^;onM!xv&<0{_GAMhx+~N zO;vY=dG=okSjaJZeuB}}_qKqsO4^$O{Gq+AVSw}Y)(J&ob`1I@Jf<7wT_RRru zvYfLESC)TD^p-j1XdJ?ebC1TU;FaL;BClu|l5%s?QQx0j9({kbMNKrmN*m@#wqjO+ zD6)!D+F`;_gzQu>@j5|2ju)yc@37G%)RiH-WqcbDxRc?F*8~_&4YrmefL;~BL5*hB z0Z%Ty_L^+tcX!syD^-^;(B~A~m98!vdtv~=`Mv%7Fu=>kiqU~0 z2eat_n~^^&Ht#vvwRVvi`EzXH){{{@ice0pysB6?R-?FMVTaQVDT^7x9+=L%j;AL_ zR+%er2>4?2$b23D${C0N|*tHfN>-55I=#aquvpq2E3>B$DFMMzotMkH-L*|qf$LGNN~aEUsNa@ z@2W3N$FK9Es=h>+g2|zdSFv#M%ffZPHlPOihwO~aK-4+Dz}#`BX+jCQ<ODm&2p!WSwJ(ydU$fa-Asngg>+^>ij=KLt=1 zw5*)iPLxJ-;kBCg!EcZM>6N7-$+ywtez$HIuTRF)tg%`0`{Mt2VOdS?p{hS4x2>wD zi|;cW$!5WYE@ta<(Xc1RxqjH;=bgJ7_`!1{nqC!T2?SiiU3@MoHV2)*fwq`4&ZkhG zSpN_UoSpd zpD#|Zd((gj;*AGqaC7dZ#$Z5RO2>VxxZDQzul?mVqS7?)yPSai_{qyHLXIrwa3qi29__#EbgAvPM1Jd_C*3(Kl?qk()134j(T{R)2zhCVOb?*}v_ckyP~0_fpi=ow z2vu0&I{7a*O|}X4u0v^7u76`4>L;kc|3erpwDymD`A|K2hPKE{^=K=V$U+aj36K^^ znN;FG6iJRwb#SW$&BZ}f{<}Y2qH_8D&4eJBzu7I6O4X4)|DplZ%Jw1T)`4_DwF^=0 zRu7`vgUI|ei0-FvWl9P)$6%(V(4Zi3XvPtLNeZ0`x59@%`M3UsdO0Xt{xXtUQ?|e9 zD0ZKb`SJWh7QupGya}a$<&onmHR)RPA^l?goIcVvUnzK zsSYIj2RuZ#>YlA90x<&|q0$Y%d_I%7lWwHdGIBPxL8{Me>H?54o32p4KjUFq zK(yRn^$4A|BCJL7=f`MK-2ijy@zHAe)Z?^Vxgy#A=qISmrSKB}zn`Labx?l`of~X_xGgi!EZG|FK+pT_CsBbL7h^I^p!pqwsK^I4^>q z1_w`$X@;GTXLNSHK>pF{d^ORkzFVDm?drG{v#Wbhy{fvp`>Ondnz763HpIW{IZD>S zTj=wc>RtZ9&r?h0ZRQJ#<3%sf{aJ|MAgT;{DyGATit;d`;y#S5hQ(EN_`+Nv96VD9 zU#TmE!+Z+iOLv8ExKSY-;8X}lJ{1DT(?T|P4`3WfRb?DxRS1W26;csER1}&Snx89+ zH&EkHDekSzgO^De1!_`QKb$^v5C7eM%lf-2%S3ku;!3<}{_4GQ6B4hlIP8^G`aVo(H5 zOS%Cs>^6XJrT7QU@fICYUK7motuU%^v8E=37{w|RQ5A&B|N0M#4M#1ndTW3~vn=@s zR_aoD`$p6FD4>Z* zTXSVqfFSX7!J0H@U|Cr-Rgt}{tX@@)y{y0(`cpafva(oLIrg$ru_dd{=1~})D&z4h z#9mgGge*dVB9@^=$eLkG$|{GS>L|okPH-kYuh3hepoJs#)$~jp zOR-Pm;s-!O0GLTCuh#*6YQKs4QL&u9iIxRe!mU++C0!kA!BX_*t65SGAG4%RrNuI9 zGd!7f{=Ch!mPF-Rf0x(kX`&oi^ai!3H{`$Hpd8vJXBN;M5rsJ}AAB5jAF)k-RzR`c zKYH3_-@&Qdu=k!;FV1n)aT?o#@cOvc@H*6U3BsemQW^gy$R76RzlkxxXdi!z{tmFH z5ZleyGI|T;igQoPf-SUF{5D@s+DaqnJ^9X7v{^0h+fK3afo&8kepx72Zl}gFc{@eO z_1i%Cmqqf8ZFGQ+$c28IPcO-^B6^St<)cM3kv@~LHi;;EQgF%kNMlDw8&wfoSyoe*3?rh6mT>=AFq|x%a&izlzRJ? zfuVfPJPqgdko@}>)VGxisMx|&Lk)VZ6Ogs4Bc1zjl*^Mp?xT;wOV2v_dfO^^XFnzO z1UfJyp-vO%6V~Bbr?*a%Fm)Y>?$!$)B_av1HipAc!2?{dG*Nh|j6Fb|un2BDKw~Y& ziZ4?FdZopVrLh-}kncKY?Dj`#F2=w4D6Le&%$5DWqwW^!fATvTFHm~) zd+N}RCpZ7771F8>aan0A+!c(=zCX~-5bskzP^vvi$A6&iqQ3Pk2T?OuwGcY}NR#XX z{oj714-lb6Po@5}3KGJrG&jfLt;4HnKA@r0Hk&cr3U8N-PEvtS)vD4_3vN&)pjGQM zW2I1>?egAJbSvESmrha3&;{!K7~WyclV6;o!B*?z+!{9RSas`i#`0C`KBuXL#g?3S zn#x+M{tj{r^tZ3N#U94i6Z-qrX?(09u}7w!qK5v5exYQtT9w+Zc2>74VQf!us}j{p zp8k~mQP@%jAn}tMt!G$_p5J<)|_vTjcb!2xJ_S>(0_U-L`z|39WBv$?+pFW38dWHPu95ufFFydv;^Av`$3_MTG|ES73tI9vlQ?jKw z>si*&oV;pT=Q6fJX^!hcwdQoVK*^RqudrJzt!|OS7#=-rm&-3uf~{)XE>L03%&6T1 z?;)*;4~yiP>1b^i8!pmrwSxA@%uDo^`#Jj=mTZ5Sp1P^L<{g&x7h``QV4SIIiSftF zbeF|(w$1THfnJqhs~E#y`)!x^U!e|v#HK910ypEB{P+sRslDZoCibfQH4&m+ki8bL z*K1NlGs;^tNpzuOYw|?zKPqk|+mqla>`9{6A6MFKRr-=d0#?|05__Cu6R=aD60VC|+#BY>yC=Bt_v(UOr-yaX z6K=$tx?pc&zb>ZK_!i?G;!Dc&_i~CBR-m!SKfxv5Au9KK-C~je%n23gZaN^()E7S+ zzg||0YY;9Pokkol9jw1I!I{nM%*x=*csuj#W$B9&6F_ZY6vTKyz7r)n0Gx;to#}u- zzM&XFNY08DGw4hCU9{*8;B6!fIw;3A0$+KuS&WE{KD>_KHr|Ds8ysT<7FP;f?VWOH zjF^Qg@5hLFwlz;_EbbsnGc<1u!Y;VzfC0*rn_@+qe#(Ykm5(J{&l`i2h^L3ArxLR8 z*0X%3Yb(o!O~e+pP)g)yO)!6@GNh?^0rGsMDWZ-Ze~ydC?W=<+!m|dy|41{@1dk^C zm*PcTqFfp76P;+C?8_im&a_f5`owVz;+X{TWFx!J76UNM7B$@az0Jk1fxvL1L~%O; z&}oT6ccR^t)&j4dV*?E2aZunSJ4fl$?7V0)VS!l+Ob^p zVcjq{^W_KKlotLQArO0$jp;6YqOIC+gFR*o=bJ1r>E(+pC!RQ~YW}pF#EVWG2;Kce zXK(QV^>_oZ6{zBSRzkfTgofhfMxMN{pXd^m_Y&TT*M+y25aM;-22VEvKIlvR#8dTy zN>U(Z!M4XiSgiB^)1gCVvcPbAMOw3&66AZi@(}hFyLl!6P5b2 zZWeU}RmjByM5{r+W2<-ZD?&Z+Uf;#<^=o`V7i>$wFLa>}2M785$OEtV1&+Epq{wpv zV1ACtn1NWT75+X0g+oN+P=hyZ2-lLQgz&P0JUj5mK=Pgx(cG49R*FcYdgW|J*t>@n z>1~wDGlRt(chPyLWhZ9cD()J9D#|ZJuGfJ{MS!#;9|-Uc(?FhD@%%KCul?aVLo+!` z42VE*K#_(a&hv*45f8HD9=lD9ww9p$`Zh7{n&V4}9D2LhWY@TSyLi$@=M5EY>a(Ej zV+;&Dg1mY1y`k0g;)jV$^ssuENUiC?Cz}ixbM5rshKrZ38S=0@MBi{8BqYHX29}cF z#Fv{KXTbF-Z=kn9Mi^~3k)jqq9A#eoYPhNyMC3F|HD>AT9im%2vsz$U4#B!Z{3itX zyJ`O04W%sy<*j#$fsIOV(TMkj%JmL0kOEDka+Q4fPVukm%O3gU2(jFQD-}CVjXO>} z^7F^tCGIBcr659Ycq!<;4luGp-B{GnD(@Om`O4NFOEt}pa4hCH!;YGHj(PDGNx}Vh+5W(ljb^h(6 zMRtv)LtxvobhnNX>E!wNQeZUdhGe(gIaVx!{kts{Lx`=pOB4p~@vL$4HTI|evEyO+ zLm^yD1bno7|HcW}5isk~6U9UX>E})q$AtR3nR5FHf0U<=4^rkiY=J-c$&+)ZVCpK@ z%B@qx4e+}EXNu_Tw#+GV#bfOQ??5jk>wmc5>y>hecAOKpED~ zRfWDsL=5(Uo{xy*&>1A z$!yV?Ve@(7tYu(i+*4{s=07FE^j6l$)Y1v%h33GU!|cmS5^hMs?G1$_u%NSL(E`z- z^`BK|;RMx>Tqs&a+JZxTsGEoZrEEE5p?D9n3SGo}t(E;21tz<(KYNjw>cb^xMZOpa zMeqEI$jAPJHv!n$w!JDsse!#eDO&np8#Ki&92 zZr&ss*ZUHGIMjz%y-^SEmVc1@Hi=esFI3kf9NZmCHx{2^+-=a_?(m zO~l_;xvKBE*7#?=j-eyKx%~|hizvGcX>X6QRTk?a^UVC2BggYT%j0Cfrl^ZWe-1m8GE9U z-?tU65)M!!wu!#=stv9(wgrfbibOPT*lic|DA+->y+$D|+PD6lB`_%Rvww;XF3k~s^Na~H?0s=2a-B|EXHC-{!*}=@ z(lqJ$Ks1kQigx!4(%i^KrWT;JAGjume<0$iot*groQ`2~{Rd(ag4OPwP1y_7B9Ga-P3Dz~n`yBuFXa{J zckdE)nq-~YdM62_9Ip45zIcLO^o)@Vi^Fh{cg=I!_cWJW#z*moTN0~JPFXZ?Hr zO3l~}+?ieJ{b8$Se9id!POpslPBTt0?%1)b$ueBTGyY-w;uqi4j3s4`Fjw-!J*S3! zqZxnY#PP+B<{vN7j8{1^Zu5sH=DemEZzBPrq@_!bO_#6{oh` z;|}c?J^2;Q_|f0!dr=qE_9=SKi{a$S7&gYZVcU3PvP@DSkKrbPhHLZS^4tnysY8F(EV?+qMoup&G# z2pvlzXLoHI5Slig#Qol z`gZ;);0=H?vpDQm;|+mF+4-%2Hw4au=o^HO03L1SXK7QAXk=H)2F@D6qstA#3xGGa z^LGJ{1gs6nJakJSD%@^~aF@K-2nr-gSnBUIH&y@RfvVxXsCl(|?Tc z;YqTZn2fa4Y13wm@9CW~{o&MUQzm$4&X_ViGc99}e^nbDw{^|@pSRWHi8}g!ZKr=r z;>t|K(FXK4guG&A4MJX(dQUVbM;U)qZ$t=Hvkx88b3aq>aK?VV4Cj z`13QZ1%G#~1eJOk^2N=2|P z6CccMKXaz0^ksvcw*vK8AvYtfJwaO89MVdG?*om`01x9kfUhYmP)eo+@3LX44Ifl6 zp0qhY+M?ooK;8zpV_XPptHH!w@_|lzo76m@mB=)sM2wkl{XqVn+|Tm{PaLR z4$oRj4i*W>GHlA-;A?Jo!}QLh&Aq5QR{qpUZ<5B%m~634me(bJJdB;lW4PCb-`eos zHauy=-)wl-WeGACn1;_($D^K32j~KZbgV=)Nz+fNA zNSzr_1J;6rb{X_h*;6+61@kO(UvBrp?KO8=2CGg_d|N=%E&tkCZ(_8aZINaJ!{#{9 zyf^Z@;A2kQfU5Z{O&OUKq6!9uSN%EX1dOe>T+>Z&K6noFuqWo7S32thkFCd(q-7&N1Nk%2@+G}BoS&MJk@_g|xV!@C zp@7Hc$hbawGnvy}&yLJ{)FQxqaHXZPaS#0warsfXs)s(#c?(9gL7wZO-_W|`F>6G; zjbKjHNXq6~tu~;HHMjz>@-cbqO?tDqQsAt@?#C^88acl?!`^ProuJBsoAjQM9u%?T z$a?Vvddif0ZqnoXbb;|<*|E*%EqF7kt;aVS>uET?IrygGi_rSdo;Wd086_ss1tiL3 z+n#!ptSVHG1qoIyCc%o$%aJGC1sH=b93OL2hPs+IZuUg%LNg}f*E213R_2{)sS~gz zp`-`uCF5gy;~vdSo7EnMcET_iB1^7J>jU5^Ha*nst7%a)Gc#^WdpK>HrhSaU33efm zL5o4zh_tln$me}92YHo{R$wCMNJlUIrN~NT_dqd!qao-CvZ$9HKcxpyHoMbo*-rp` z4C&i2`dr{Fx%62xrnkR6HDlJ~)M;rM){-5CIy>$1fZ1lX;yGmfZi{xT1z#Y|V#$@s zz4a!}OppziV|(j2WOao8GIbUzuUEFQtkc}ei+pYsj;t)-*eG(5|1ZEC(D)LN+a@FL5a0^C4NnVyY@KlMi&m8~QFtdZ*8^H?HtnN#a83i= z4RUxNy-i|^EQ?LW#9vC>B{gvaKFcfb-_V0!T(4YuO+`PLHtRSU@&8(*b#J$pmDvKVj!TWy58F zJhc*#IoyZ7G;Mn7gK1bo4EjGRKkBQG99fDAd+=4y^Q_E_+2b<@PDz_K0Y*|a-hgsu z^rBraunc%ij(K1RUziQM0CIc5@&#c>2uQndne4 zew$s_i!?jZEZLoyzd3-X(8nH}M=t_${z+T)m_FOYv4E^H;66)LC`IN>D?=5iHHS10 zF)&OfdlFYN;S1DT4_q1Epgb;DQwFFs2G9X!^9AJi2csP}JJTAj(kE5f zGI)W}CL@nE_8>+V7%ek#qdi*gz@goenwhF;?}O3dNHY_GEp05)Jz2N!1+oHPu;}IK zfqJ7`m86U9qJXijEon{{+q24K9NLgH-cic%?L(UTER(|r=~F{{Lq}K%&IiLV?Zw>xTY88xeurYO6sR(VG1BX>PIGfk@i z6Kzpe2I&k16SE$jH69w@9;2H+15ECR$>A++KZcnMJ!Uuu=6^q|Ri-k&dX_fLE*Lw{ zst^T}!4>x?vj@gh#YWn2n^2BjKdBDav;1L(?EmhE2a=?q&{iwAOlZdygjT3_PNiZ@ zp94MnwXDWk3=A`89E2;hAM)#Mr$;MYfSaV!*t`_fwe@h`_rt`q^S)n8QJcelI5Cwf zEwtobobS-0AaIsIreeIYk|NV*X>)(96o-bRVsBf#fn9(ZikeQ?RR(Ie*kx?uxty6R z#x61nsoPM-8W-?WcyFtaO^4{sT=+A}u+tr6@(?{Hq6*a}p)G$C{Aoku_;Y}e9L^$s?q}juG1CTo#uSR4P{mT`W_`j@Mg}O$ItnnvS(~TU z#}RyXXJ4Qb&L4_2i?;}ngBM=_hU3NG9!T&1*mi!_UU0E|+ygI6ymJ>wA_!r38V$&S zriL&JJa?09CO!b<{eKn8S#lp+OzZ)juK$O&4iMk#zj2}-*-GEx=;|N1T<;=6ySUp= Q!2Z_0QxEyrO8v9{2Q@YN0RR91 diff --git a/lib/challenge.go b/lib/challenge.go index 5eba175..208f8fa 100644 --- a/lib/challenge.go +++ b/lib/challenge.go @@ -25,12 +25,17 @@ type ChallengeInformation struct { IssuedAt *jwt.NumericDate `json:"iat,omitempty"` } -func getRequestAddress(r *http.Request) net.IP { - //TODO: verified upstream - ipStr := r.Header.Get("X-Real-Ip") - if ipStr == "" { - ipStr = strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0] +func getRequestAddress(r *http.Request, clientHeader string) net.IP { + var ipStr string + if clientHeader != "" { + ipStr = r.Header.Get(clientHeader) } + if ipStr != "" { + // handle X-Forwarded-For + ipStr = strings.Split(ipStr, ",")[0] + } + + // fallback if ipStr == "" { parts := strings.Split(r.RemoteAddr, ":") // drop port @@ -44,7 +49,7 @@ func (state *State) GetChallengeKeyForRequest(name string, until time.Time, r *h hasher.Write([]byte("challenge\x00")) hasher.Write([]byte(name)) hasher.Write([]byte{0}) - hasher.Write(getRequestAddress(r).To16()) + hasher.Write(getRequestAddress(r, state.Settings.ClientIpHeader).To16()) hasher.Write([]byte{0}) // specific headers diff --git a/lib/challenge/interface.go b/lib/challenge/wasm/interface/interface.go similarity index 99% rename from lib/challenge/interface.go rename to lib/challenge/wasm/interface/interface.go index bdd4b14..4630ca6 100644 --- a/lib/challenge/interface.go +++ b/lib/challenge/wasm/interface/interface.go @@ -1,4 +1,4 @@ -package challenge +package _interface import ( "encoding/json" diff --git a/lib/challenge/wasm/interface/interface_generic.go b/lib/challenge/wasm/interface/interface_generic.go new file mode 100644 index 0000000..a43ef83 --- /dev/null +++ b/lib/challenge/wasm/interface/interface_generic.go @@ -0,0 +1,10 @@ +//go:build !tinygo || !wasip1 + +package _interface + +func PtrToBytes(ptr uint32, size uint32) []byte { panic("not implemented") } +func BytesToPtr(s []byte) (uint32, uint32) { panic("not implemented") } +func BytesToLeakedPtr(s []byte) (uint32, uint32) { panic("not implemented") } +func PtrToString(ptr uint32, size uint32) string { panic("not implemented") } +func StringToPtr(s string) (uint32, uint32) { panic("not implemented") } +func StringToLeakedPtr(s string) (uint32, uint32) { panic("not implemented") } diff --git a/lib/challenge/utils_tinygo.go b/lib/challenge/wasm/interface/interface_tinygo.go similarity index 99% rename from lib/challenge/utils_tinygo.go rename to lib/challenge/wasm/interface/interface_tinygo.go index f75ffa5..82546de 100644 --- a/lib/challenge/utils_tinygo.go +++ b/lib/challenge/wasm/interface/interface_tinygo.go @@ -1,6 +1,6 @@ //go:build tinygo -package challenge +package _interface // #include import "C" diff --git a/lib/challenge/utils_generic.go b/lib/challenge/wasm/runner.go similarity index 57% rename from lib/challenge/utils_generic.go rename to lib/challenge/wasm/runner.go index eac9ee4..7c74fae 100644 --- a/lib/challenge/utils_generic.go +++ b/lib/challenge/wasm/runner.go @@ -1,10 +1,7 @@ -//go:build !tinygo || !wasip1 - -package challenge +package wasm import ( "context" - "encoding/json" "errors" "fmt" "github.com/tetratelabs/wazero" @@ -123,73 +120,3 @@ func (r *Runner) Instantiate(key string, f func(ctx context.Context, mod api.Mod return f(r.context, mod) } - -func MakeChallengeCall(ctx context.Context, mod api.Module, in MakeChallengeInput) (*MakeChallengeOutput, error) { - makeChallengeFunc := mod.ExportedFunction("MakeChallenge") - malloc := mod.ExportedFunction("malloc") - free := mod.ExportedFunction("free") - - inData, err := json.Marshal(in) - if err != nil { - return nil, err - } - - mallocResult, err := malloc.Call(ctx, uint64(len(inData))) - if err != nil { - return nil, err - } - defer free.Call(ctx, mallocResult[0]) - if !mod.Memory().Write(uint32(mallocResult[0]), inData) { - return nil, errors.New("could not write memory") - } - result, err := makeChallengeFunc.Call(ctx, uint64(NewAllocation(uint32(mallocResult[0]), uint32(len(inData))))) - if err != nil { - return nil, err - } - resultPtr := Allocation(result[0]) - outData, ok := mod.Memory().Read(resultPtr.Pointer(), resultPtr.Size()) - if !ok { - return nil, errors.New("could not read result") - } - defer free.Call(ctx, uint64(resultPtr.Pointer())) - - var out MakeChallengeOutput - err = json.Unmarshal(outData, &out) - if err != nil { - return nil, err - } - return &out, nil -} - -func VerifyChallengeCall(ctx context.Context, mod api.Module, in VerifyChallengeInput) (VerifyChallengeOutput, error) { - verifyChallengeFunc := mod.ExportedFunction("VerifyChallenge") - malloc := mod.ExportedFunction("malloc") - free := mod.ExportedFunction("free") - - inData, err := json.Marshal(in) - if err != nil { - return VerifyChallengeOutputError, err - } - - mallocResult, err := malloc.Call(ctx, uint64(len(inData))) - if err != nil { - return VerifyChallengeOutputError, err - } - defer free.Call(ctx, mallocResult[0]) - if !mod.Memory().Write(uint32(mallocResult[0]), inData) { - return VerifyChallengeOutputError, errors.New("could not write memory") - } - result, err := verifyChallengeFunc.Call(ctx, uint64(NewAllocation(uint32(mallocResult[0]), uint32(len(inData))))) - if err != nil { - return VerifyChallengeOutputError, err - } - - return VerifyChallengeOutput(result[0]), nil -} - -func PtrToBytes(ptr uint32, size uint32) []byte { panic("not implemented") } -func BytesToPtr(s []byte) (uint32, uint32) { panic("not implemented") } -func BytesToLeakedPtr(s []byte) (uint32, uint32) { panic("not implemented") } -func PtrToString(ptr uint32, size uint32) string { panic("not implemented") } -func StringToPtr(s string) (uint32, uint32) { panic("not implemented") } -func StringToLeakedPtr(s string) (uint32, uint32) { panic("not implemented") } diff --git a/lib/challenge/wasm/utils.go b/lib/challenge/wasm/utils.go new file mode 100644 index 0000000..b9482b7 --- /dev/null +++ b/lib/challenge/wasm/utils.go @@ -0,0 +1,72 @@ +package wasm + +import ( + "context" + "encoding/json" + "errors" + "git.gammaspectra.live/git/go-away/lib/challenge/wasm/interface" + "github.com/tetratelabs/wazero/api" +) + +func MakeChallengeCall(ctx context.Context, mod api.Module, in _interface.MakeChallengeInput) (*_interface.MakeChallengeOutput, error) { + makeChallengeFunc := mod.ExportedFunction("MakeChallenge") + malloc := mod.ExportedFunction("malloc") + free := mod.ExportedFunction("free") + + inData, err := json.Marshal(in) + if err != nil { + return nil, err + } + + mallocResult, err := malloc.Call(ctx, uint64(len(inData))) + if err != nil { + return nil, err + } + defer free.Call(ctx, mallocResult[0]) + if !mod.Memory().Write(uint32(mallocResult[0]), inData) { + return nil, errors.New("could not write memory") + } + result, err := makeChallengeFunc.Call(ctx, uint64(_interface.NewAllocation(uint32(mallocResult[0]), uint32(len(inData))))) + if err != nil { + return nil, err + } + resultPtr := _interface.Allocation(result[0]) + outData, ok := mod.Memory().Read(resultPtr.Pointer(), resultPtr.Size()) + if !ok { + return nil, errors.New("could not read result") + } + defer free.Call(ctx, uint64(resultPtr.Pointer())) + + var out _interface.MakeChallengeOutput + err = json.Unmarshal(outData, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func VerifyChallengeCall(ctx context.Context, mod api.Module, in _interface.VerifyChallengeInput) (_interface.VerifyChallengeOutput, error) { + verifyChallengeFunc := mod.ExportedFunction("VerifyChallenge") + malloc := mod.ExportedFunction("malloc") + free := mod.ExportedFunction("free") + + inData, err := json.Marshal(in) + if err != nil { + return _interface.VerifyChallengeOutputError, err + } + + mallocResult, err := malloc.Call(ctx, uint64(len(inData))) + if err != nil { + return _interface.VerifyChallengeOutputError, err + } + defer free.Call(ctx, mallocResult[0]) + if !mod.Memory().Write(uint32(mallocResult[0]), inData) { + return _interface.VerifyChallengeOutputError, errors.New("could not write memory") + } + result, err := verifyChallengeFunc.Call(ctx, uint64(_interface.NewAllocation(uint32(mallocResult[0]), uint32(len(inData))))) + if err != nil { + return _interface.VerifyChallengeOutputError, err + } + + return _interface.VerifyChallengeOutput(result[0]), nil +} diff --git a/lib/http.go b/lib/http.go index edc08e2..2fc9cf2 100644 --- a/lib/http.go +++ b/lib/http.go @@ -125,10 +125,10 @@ func (state *State) addTiming(w http.ResponseWriter, name, desc string, duration } } -func GetLoggerForRequest(r *http.Request) *slog.Logger { +func GetLoggerForRequest(r *http.Request, clientHeader string) *slog.Logger { return slog.With( "request_id", r.Header.Get("X-Away-Id"), - "remote_address", getRequestAddress(r), + "remote_address", getRequestAddress(r, clientHeader), "user_agent", r.UserAgent(), "host", r.Host, "path", r.URL.Path, @@ -136,6 +136,10 @@ func GetLoggerForRequest(r *http.Request) *slog.Logger { ) } +func (state *State) logger(r *http.Request) *slog.Logger { + return GetLoggerForRequest(r, state.Settings.ClientIpHeader) +} + func (state *State) handleRequest(w http.ResponseWriter, r *http.Request) { host := r.Host @@ -145,7 +149,7 @@ func (state *State) handleRequest(w http.ResponseWriter, r *http.Request) { return } - lg := GetLoggerForRequest(r) + lg := state.logger(r) start := time.Now() @@ -153,7 +157,7 @@ func (state *State) handleRequest(w http.ResponseWriter, r *http.Request) { env := map[string]any{ "host": host, "method": r.Method, - "remoteAddress": getRequestAddress(r), + "remoteAddress": getRequestAddress(r, state.Settings.ClientIpHeader), "userAgent": r.UserAgent(), "path": r.URL.Path, "query": func() map[string]string { @@ -259,7 +263,7 @@ func (state *State) handleRequest(w http.ResponseWriter, r *http.Request) { if rule.Action == policy.RuleActionCHECK { goto nextRule } - GetLoggerForRequest(r).Warn("challenge passed", "rule", rule.Name, "rule_hash", rule.Hash, "challenge", challengeName) + state.logger(r).Warn("challenge passed", "rule", rule.Name, "rule_hash", rule.Hash, "challenge", challengeName) // we pass the challenge early! r.Header.Set(fmt.Sprintf("X-Away-Challenge-%s-Verify", challengeName), "PASS") @@ -374,15 +378,15 @@ func (state *State) setupRoutes() error { state.addTiming(w, "challenge-verify", "Verify client challenge", time.Since(start)) if err != nil { - GetLoggerForRequest(r).Error(fmt.Errorf("challenge error: %w", err).Error(), "challenge", challengeName, "redirect", r.FormValue("redirect")) + state.logger(r).Error(fmt.Errorf("challenge error: %w", err).Error(), "challenge", challengeName, "redirect", r.FormValue("redirect")) return err } else if !ok { - GetLoggerForRequest(r).Warn("challenge failed", "challenge", challengeName, "redirect", r.FormValue("redirect")) + state.logger(r).Warn("challenge failed", "challenge", challengeName, "redirect", r.FormValue("redirect")) ClearCookie(CookiePrefix+challengeName, w) _ = state.errorPage(w, r.Header.Get("X-Away-Id"), http.StatusForbidden, fmt.Errorf("access denied: failed challenge %s", challengeName)) return nil } - GetLoggerForRequest(r).Info("challenge passed", "challenge", challengeName, "redirect", r.FormValue("redirect")) + state.logger(r).Info("challenge passed", "challenge", challengeName, "redirect", r.FormValue("redirect")) token, err := state.IssueChallengeToken(challengeName, key, []byte(result), expiry) if err != nil { diff --git a/lib/state.go b/lib/state.go index 1f69158..72818a7 100644 --- a/lib/state.go +++ b/lib/state.go @@ -12,7 +12,8 @@ import ( "errors" "fmt" "git.gammaspectra.live/git/go-away/embed" - "git.gammaspectra.live/git/go-away/lib/challenge" + "git.gammaspectra.live/git/go-away/lib/challenge/wasm" + "git.gammaspectra.live/git/go-away/lib/challenge/wasm/interface" "git.gammaspectra.live/git/go-away/lib/condition" "git.gammaspectra.live/git/go-away/lib/policy" "git.gammaspectra.live/git/go-away/utils/inline" @@ -44,7 +45,7 @@ type State struct { Networks map[string]cidranger.Ranger - Wasm *challenge.Runner + Wasm *wasm.Runner Challenges map[string]ChallengeState @@ -101,6 +102,7 @@ type StateSettings struct { PackageName string ChallengeTemplate string ChallengeTemplateTheme string + ClientIpHeader string } func NewState(p policy.Policy, settings StateSettings) (state *State, err error) { @@ -118,7 +120,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error) if proxy, ok := backend.(*httputil.ReverseProxy); ok { if proxy.ErrorHandler == nil { proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) { - GetLoggerForRequest(r).Error(err.Error()) + state.logger(r).Error(err.Error()) _ = state.errorPage(w, r.Header.Get("X-Away-Id"), http.StatusBadGateway, err) } } @@ -186,7 +188,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error) state.Networks[k] = ranger } - state.Wasm = challenge.NewRunner(true) + state.Wasm = wasm.NewRunner(true) state.Challenges = make(map[string]ChallengeState) @@ -429,12 +431,12 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error) if ok, err := c.Verify(key, result); err != nil { return err } else if !ok { - GetLoggerForRequest(r).Warn("challenge failed", "challenge", challengeName, "redirect", r.FormValue("redirect")) + state.logger(r).Warn("challenge failed", "challenge", challengeName, "redirect", r.FormValue("redirect")) ClearCookie(CookiePrefix+challengeName, w) _ = state.errorPage(w, r.Header.Get("X-Away-Id"), http.StatusForbidden, fmt.Errorf("access denied: failed challenge %s", challengeName)) return nil } - GetLoggerForRequest(r).Warn("challenge passed", "challenge", challengeName, "redirect", r.FormValue("redirect")) + state.logger(r).Warn("challenge passed", "challenge", challengeName, "redirect", r.FormValue("redirect")) token, err := state.IssueChallengeToken(challengeName, key, []byte(result), expiry) if err != nil { @@ -476,7 +478,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error) c.MakeChallenge = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { err := state.Wasm.Instantiate(challengeName, func(ctx context.Context, mod api.Module) (err error) { - in := challenge.MakeChallengeInput{ + in := _interface.MakeChallengeInput{ Key: state.GetChallengeKeyForRequest(challengeName, time.Now().UTC().Add(DefaultValidity).Round(DefaultValidity), r), Parameters: p.Parameters, Headers: inline.MIMEHeader(r.Header), @@ -486,7 +488,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error) return err } - out, err := challenge.MakeChallengeCall(ctx, mod, in) + out, err := wasm.MakeChallengeCall(ctx, mod, in) if err != nil { return err } @@ -508,21 +510,21 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error) c.Verify = func(key []byte, result string) (ok bool, err error) { err = state.Wasm.Instantiate(challengeName, func(ctx context.Context, mod api.Module) (err error) { - in := challenge.VerifyChallengeInput{ + in := _interface.VerifyChallengeInput{ Key: key, Parameters: p.Parameters, Result: []byte(result), } - out, err := challenge.VerifyChallengeCall(ctx, mod, in) + out, err := wasm.VerifyChallengeCall(ctx, mod, in) if err != nil { return err } - if out == challenge.VerifyChallengeOutputError { + if out == _interface.VerifyChallengeOutputError { return errors.New("error checking challenge") } - ok = out == challenge.VerifyChallengeOutputOK + ok = out == _interface.VerifyChallengeOutputOK return nil }) if err != nil {