@@ -6,13 +6,15 @@ import (
66 "errors"
77 "fmt"
88 "io"
9+ "net"
910 "net/http"
1011 "strconv"
1112 "time"
1213
1314 "github.com/labstack/echo/v4"
1415 "github.com/modfin/twofer/api"
1516 "github.com/modfin/twofer/internal/bankid"
17+ "github.com/modfin/twofer/internal/ordertoken"
1618 "github.com/modfin/twofer/internal/sse"
1719 "github.com/modfin/twofer/stream"
1820)
@@ -21,16 +23,16 @@ const qrCodeUpdatePeriod = time.Second
2123
2224type NewStreamEncoder func (http.ResponseWriter ) (stream.Encoder , error )
2325
24- func RegisterBankIDServer (e * echo.Echo , client * bankid.API , newEncoder NewStreamEncoder ) {
26+ func RegisterBankIDServer (e * echo.Echo , client * bankid.API , otm * ordertoken. Manager , newEncoder NewStreamEncoder ) {
2527 e .POST ("/bankid/v6/auth" , auth (client ))
2628 e .POST ("/bankid/v6/authv2" , authSign (client .Auth , client .WatchForChangeV2 , qrCodeUpdatePeriod , newEncoder )) // Deprecated: Don't use
27- e .POST ("/bankid/v6/authv3" , authSignV3 (client .Auth , qrCodeUpdatePeriod , newEncoder )) // Same as 'auth' except won't poll BankID collect API (since a completed/failed orderRef can only be collected once)
29+ e .POST ("/bankid/v6/authv3" , authSignV3 (client .Auth , qrCodeUpdatePeriod , newEncoder , otm )) // Same as 'auth' except won't poll BankID collect API (since a completed/failed orderRef can only be collected once)
2830 e .POST ("/bankid/v6/sign" , sign (client ))
2931 e .POST ("/bankid/v6/signv2" , authSign (client .Sign , client .WatchForChangeV2 , qrCodeUpdatePeriod , newEncoder )) // Deprecated: Don't use
30- e .POST ("/bankid/v6/signv3" , authSignV3 (client .Sign , qrCodeUpdatePeriod , newEncoder )) // Same as 'sign' except won't poll BankID collect API (since a completed/failed orderRef can only be collected once)
32+ e .POST ("/bankid/v6/signv3" , authSignV3 (client .Sign , qrCodeUpdatePeriod , newEncoder , otm )) // Same as 'sign' except won't poll BankID collect API (since a completed/failed orderRef can only be collected once)
3133 e .POST ("/bankid/v6/change" , change (client ))
3234 e .POST ("/bankid/v6/collect" , collect (client ))
33- e .POST ("/bankid/v6/collectV3" , collectV3 (client ))
35+ e .POST ("/bankid/v6/collectV3" , collectV3 (client , otm ))
3436 e .POST ("/bankid/v6/cancel" , cancel (client ))
3537 e .POST ("/bankid/v6/cancelV3" , cancelV3 (client ))
3638}
@@ -490,14 +492,17 @@ func bankIdv6ErrorResponseV3(err error, detail string) api.BankIdv6ErrorResponse
490492// or change endpoints after the first QR-code has been returned. It also returns one or more
491493// api.BankIdV6AuthSignResponseV3 structs for a successful auth/sign request. For failed requests,
492494// a api.BankIdv6ErrorResponseV3 is returned instead.
493- func authSignV3 (authOrSignFn authSignFn , qrPeriod time.Duration , newStreamEncoder NewStreamEncoder ) func (echo.Context ) error {
495+ func authSignV3 (authOrSignFn authSignFn , qrPeriod time.Duration , newStreamEncoder NewStreamEncoder , otm * ordertoken. Manager ) func (echo.Context ) error {
494496 return func (c echo.Context ) error {
495497 request , err := readBody [api.BankIdv6AuthSignRequestV3 ](c .Request ().Body )
496498 if err != nil {
497499 fmt .Printf ("ERR: read request body error: %v\n " , err )
498500 return c .JSON (http .StatusBadRequest , bankIdv6ErrorResponseV3 (err , "read request body error" ))
499501 }
500-
502+ if ip := net .ParseIP (request .EndUserIp ); ip == nil {
503+ fmt .Printf ("ERR: error parsing endUserIp\n " )
504+ return c .JSON (http .StatusBadRequest , bankIdv6ErrorResponseV3 (nil , "error parsing endUserIp" ))
505+ }
501506 // Convert from public API to internal struct
502507 br := bankid.Requirement {
503508 PinCode : request .PinCode ,
@@ -518,11 +523,25 @@ func authSignV3(authOrSignFn authSignFn, qrPeriod time.Duration, newStreamEncode
518523 return c .JSON (http .StatusBadRequest , bankIdv6ErrorResponseV3 (err , "auth/sign request error" ))
519524 }
520525
526+ orderToken := ""
527+ if otm != nil {
528+ t , err := otm .Create (request .OrderTokenExpire , ordertoken.Payload {
529+ OrderRef : res .OrderRef ,
530+ EndUserIp : request .EndUserIp ,
531+ })
532+ if err != nil {
533+ fmt .Printf ("ERR: error creating order token: %v\n " , err )
534+ return c .JSON (http .StatusBadRequest , bankIdv6ErrorResponseV3 (err , "error creating order token" ))
535+ }
536+ orderToken = t
537+ }
538+
521539 bankIdV6AuthSignResponseV3 := func (r * bankid.AuthSignResponse , qrNo int ) api.BankIdV6AuthSignResponseV3 {
522540 return api.BankIdV6AuthSignResponseV3 {
523- OrderRef : r .OrderRef ,
524- URI : fmt .Sprintf ("bankid:///?autostarttoken=%s&redirect=null" , r .AutoStartToken ),
525- QR : r .BuildQrCode (qrNo ),
541+ OrderRef : r .OrderRef ,
542+ URI : fmt .Sprintf ("bankid:///?autostarttoken=%s&redirect=null" , r .AutoStartToken ),
543+ QR : r .BuildQrCode (qrNo ),
544+ OrderToken : orderToken ,
526545 }
527546 }
528547
@@ -554,14 +573,25 @@ func authSignV3(authOrSignFn authSignFn, qrPeriod time.Duration, newStreamEncode
554573
555574// Pretty much the same as collect and change, except that it will return an api.BankIdV6CollectResponseV3 struct for
556575// successful requests, for failed requests, an api.BankIdv6ErrorResponseV3 is returned instead.
557- func collectV3 (client * bankid.API ) func (echo.Context ) error {
576+ func collectV3 (client * bankid.API , otm * ordertoken. Manager ) func (echo.Context ) error {
558577 return func (c echo.Context ) error {
559578 request , err := readBody [api.BankIdv6CollectRequestV3 ](c .Request ().Body )
560579 if err != nil {
561580 fmt .Printf ("ERR: read request body error: %v\n " , err )
562581 return c .JSON (http .StatusBadRequest , bankIdv6ErrorResponseV3 (err , "read request body error" ))
563582 }
564583
584+ if otm != nil {
585+ claims , err := otm .Parse (request .OrderToken , request .EndUserIp )
586+ if err != nil && errors .Is (err , ordertoken .ErrOrderIpMismatch ) {
587+ return c .JSON (http .StatusBadRequest , bankIdv6ErrorResponseV3 (err , "order token ip mismatch with request ip" ))
588+ }
589+ if err != nil {
590+ return c .JSON (http .StatusInternalServerError , bankIdv6ErrorResponseV3 (err , "error parsing order token" ))
591+ }
592+ request .OrderRef = claims .OrderRef
593+ }
594+
565595 var res * bankid.CollectResponse
566596 if request .WaitForChange || request .WaitUntilFinished {
567597 res , err = client .ChangeV3 (c .Request ().Context (), & bankid.ChangeRequest {
@@ -575,6 +605,9 @@ func collectV3(client *bankid.API) func(echo.Context) error {
575605 fmt .Printf ("ERR: collect request error: %v\n " , err )
576606 return c .JSON (http .StatusBadRequest , bankIdv6ErrorResponseV3 (err , "collect request error" ))
577607 }
608+ if otm != nil && res .CompletionData .Device .IpAddress != request .EndUserIp {
609+ return c .JSON (http .StatusBadRequest , bankIdv6ErrorResponseV3 (nil , "order token ip mismatch with device ip" ))
610+ }
578611
579612 reply := api.BankIdV6CollectResponseV3 {
580613 OrderRef : res .OrderRef ,
0 commit comments