Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: update link qr flow
Browse files Browse the repository at this point in the history
martinsaporiti committed Sep 12, 2024
1 parent 69930d4 commit 3fcd836
Showing 19 changed files with 199 additions and 152 deletions.
9 changes: 5 additions & 4 deletions api/api.yaml
Original file line number Diff line number Diff line change
@@ -973,6 +973,11 @@ paths:
name: uuid
path: github.com/google/uuid
example: 8edd8112-c415-11ed-b036-debe37e1cbd6
- in: query
name: issuer
schema:
type: string

responses:
'200':
description: A json to generate a QR code
@@ -1262,7 +1267,6 @@ paths:
- Links
parameters:
- $ref: '#/components/parameters/pathIdentifier'
- $ref: '#/components/parameters/sessionID'
- $ref: '#/components/parameters/linkID'
requestBody:
required: true
@@ -2202,9 +2206,6 @@ components:
universalLink:
type: string
example: https://wallet.privado.id#request_uri=url
sessionID:
type: string
example: ab5d5dbf-aaaa-bbbb-b983-f48afea64e05
linkDetail:
$ref: '#/components/schemas/LinkSimple'

30 changes: 10 additions & 20 deletions internal/api/api.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions internal/api/authentication_test.go
Original file line number Diff line number Diff line change
@@ -308,3 +308,18 @@ func checkQRfetchURL(t *testing.T, qrLink string) string {
require.NoError(t, err)
return fetchURL
}

func checkQRFetchURLForLinks(t *testing.T, qrLink string) string {
t.Helper()
qrURL, err := url.Parse(qrLink)
require.NoError(t, err)
assert.Equal(t, "iden3comm", qrURL.Scheme)
vals, err := url.ParseQuery(qrURL.RawQuery)
require.NoError(t, err)
val, found := vals["request_uri"]
require.True(t, found)
fetchURL, err := url.QueryUnescape(val[0])
require.NoError(t, err)
fetchURL = fetchURL + "&issuer=" + vals["issuer"][0]
return fetchURL
}
21 changes: 11 additions & 10 deletions internal/api/links.go
Original file line number Diff line number Diff line change
@@ -92,9 +92,18 @@ func (s *Server) CreateLinkQrCodeCallback(ctx context.Context, request CreateLin
return CreateLinkQrCodeCallback400JSONResponse{N400JSONResponse{"Cannot proceed with empty body"}}, nil
}

offer, err := s.linkService.ProcessCallBack(ctx, *request.Body, request.Params.SessionID, request.Params.LinkID, s.cfg.ServerUrl)
issuerDID, err := w3c.ParseDID(request.Identifier)
if err != nil {
log.Error(ctx, "parsing issuer did", "err", err, "did", request.Identifier)
return CreateLinkQrCodeCallback400JSONResponse{N400JSONResponse{Message: "invalid issuer did"}}, nil
}

offer, err := s.linkService.ProcessCallBack(ctx, *issuerDID, *request.Body, request.Params.LinkID, s.cfg.ServerUrl)
if err != nil {
log.Error(ctx, "error issuing the claim", "error", err)
if errors.Is(err, services.ErrLinkAlreadyExpired) || errors.Is(err, services.ErrLinkMaxExceeded) || errors.Is(err, services.ErrLinkInactive) {
return CreateLinkQrCodeCallback400JSONResponse{N400JSONResponse{Message: "error: " + err.Error()}}, nil
}
return CreateLinkQrCodeCallback500JSONResponse{
N500JSONResponse{
Message: "error processing the callback",
@@ -188,22 +197,14 @@ func (s *Server) CreateLinkQrCode(ctx context.Context, req CreateLinkQrCodeReque
return CreateLinkQrCode500JSONResponse{N500JSONResponse{"Unexpected error while creating qr code"}}, nil
}

// Backward compatibility. If the type is raw, we return the raw qr code
qrCodeRaw, err := s.qrService.Find(ctx, createLinkQrCodeResponse.QrID)
if err != nil {
log.Error(ctx, "qr store. Finding qr", "err", err, "id", createLinkQrCodeResponse.QrID)
return CreateLinkQrCode500JSONResponse{N500JSONResponse{"error looking for qr body"}}, nil
}

return CreateLinkQrCode200JSONResponse{
Issuer: IssuerDescription{
DisplayName: s.cfg.IssuerName,
Logo: s.cfg.IssuerLogo,
},
DeepLink: createLinkQrCodeResponse.DeepLink,
UniversalLink: createLinkQrCodeResponse.UniversalLink,
QrCodeRaw: string(qrCodeRaw),
SessionID: createLinkQrCodeResponse.SessionID,
QrCodeRaw: createLinkQrCodeResponse.QrCodeRaw,
LinkDetail: getLinkSimpleResponse(*createLinkQrCodeResponse.Link),
}, nil
}
7 changes: 2 additions & 5 deletions internal/api/links_test.go
Original file line number Diff line number Diff line change
@@ -1001,7 +1001,7 @@ func TestServer_CreateLinkQRCode(t *testing.T) {

realQR := protocol.AuthorizationRequestMessage{}

qrLink := checkQRfetchURL(t, response.DeepLink)
qrLink := checkQRFetchURLForLinks(t, response.DeepLink)

// Let's see that universal link is correct
assert.Equal(t, server.cfg.UniversalLinks.BaseUrl+"#request_uri="+qrLink, response.UniversalLink)
@@ -1017,12 +1017,9 @@ func TestServer_CreateLinkQRCode(t *testing.T) {

assert.NotNil(t, realQR.Body)
assert.Equal(t, "authentication", realQR.Body.Reason)
callbackArr := strings.Split(realQR.Body.CallbackURL, "sessionID")
callbackArr := strings.Split(realQR.Body.CallbackURL, "linkID")
assert.True(t, len(callbackArr) == 2)
assert.Equal(t, callBack, callbackArr[0])
params := strings.Split(callbackArr[1], "linkID")
assert.True(t, len(params) == 2)
assert.NotNil(t, realQR.ID)
assert.Equal(t, "https://iden3-communication.io/authorization/1.0/request", string(realQR.Type))
assert.Equal(t, "application/iden3comm-plain-json", string(realQR.Typ))
assert.Equal(t, did.String(), realQR.From)
22 changes: 21 additions & 1 deletion internal/api/qrcode.go
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@ package api
import (
"context"

"github.com/iden3/go-iden3-core/v2/w3c"

"github.com/polygonid/sh-id-platform/internal/log"
)

@@ -15,7 +17,25 @@ func (s *Server) GetQrFromStore(ctx context.Context, request GetQrFromStoreReque
body, err := s.qrService.Find(ctx, *request.Params.Id)
if err != nil {
log.Error(ctx, "qr store. Finding qr", "err", err, "id", *request.Params.Id)
return GetQrFromStore500JSONResponse{N500JSONResponse{"error looking for qr body"}}, nil

if request.Params.Issuer == nil {
return GetQrFromStore400JSONResponse{N400JSONResponse{"error looking for qr body"}}, nil
}

issuerDID, err := w3c.ParseDID(*request.Params.Issuer)
if err != nil {
log.Error(ctx, "parsing issuer did", "err", err, "did", *request.Params.Issuer)
return GetQrFromStore400JSONResponse{N400JSONResponse{"invalid issuer did"}}, nil
}

link, err := s.linkService.GetByID(ctx, *issuerDID, *request.Params.Id)

if link.AuthorizationRequestMessage == nil {
log.Error(ctx, "qr store. Finding qr", "err", err, "id", *request.Params.Id)
return GetQrFromStore400JSONResponse{N400JSONResponse{"error looking for qr body"}}, nil
}

return NewQrContentResponse(link.AuthorizationRequestMessage.Bytes), nil
}
return NewQrContentResponse(body), nil
}
32 changes: 17 additions & 15 deletions internal/core/domain/link.go
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import (
"github.com/iden3/go-schema-processor/v2/verifiable"
"github.com/iden3/iden3comm/v2"
"github.com/iden3/iden3comm/v2/protocol"
"github.com/jackc/pgtype"

"github.com/polygonid/sh-id-platform/internal/common"
)
@@ -62,21 +63,22 @@ type LinkCoreDID w3c.DID

// Link - represents a credential offer
type Link struct {
ID uuid.UUID
IssuerDID LinkCoreDID
CreatedAt time.Time
MaxIssuance *int
ValidUntil *time.Time
SchemaID uuid.UUID
CredentialExpiration *time.Time
CredentialSignatureProof bool
CredentialMTPProof bool
CredentialSubject CredentialSubject
Active bool
Schema *Schema
IssuedClaims int // TODO: Give a value when link redemption is implemented
RefreshService *verifiable.RefreshService
DisplayMethod *verifiable.DisplayMethod
ID uuid.UUID
IssuerDID LinkCoreDID
CreatedAt time.Time
MaxIssuance *int
ValidUntil *time.Time
SchemaID uuid.UUID
CredentialExpiration *time.Time
CredentialSignatureProof bool
CredentialMTPProof bool
CredentialSubject CredentialSubject
Active bool
Schema *Schema
IssuedClaims int // TODO: Give a value when link redemption is implemented
RefreshService *verifiable.RefreshService
DisplayMethod *verifiable.DisplayMethod
AuthorizationRequestMessage *pgtype.JSONB `json:"authorization_request_message"`
}

// NewLink - Constructor
1 change: 1 addition & 0 deletions internal/core/ports/identity_service.go
Original file line number Diff line number Diff line change
@@ -54,6 +54,7 @@ type IdentityService interface {
GetStates(ctx context.Context, issuerDID w3c.DID, filter *GetStateTransactionsRequest) ([]domain.IdentityState, uint, error)
CreateAuthenticationQRCode(ctx context.Context, serverURL string, issuerDID w3c.DID) (*CreateAuthenticationQRCodeResponse, error)
Authenticate(ctx context.Context, message string, sessionID uuid.UUID, serverURL string) (*protocol.AuthorizationResponseMessage, error)
AuthenticateWithRequest(ctx context.Context, sessionID *uuid.UUID, authReq protocol.AuthorizationRequestMessage, message string, serverURL string) (*protocol.AuthorizationResponseMessage, error)
GetFailedState(ctx context.Context, identifier w3c.DID) (*domain.IdentityState, error)
PublishGenesisStateToRHS(ctx context.Context, did *w3c.DID) error
UpdateIdentityDisplayName(ctx context.Context, did w3c.DID, displayName string) error
2 changes: 2 additions & 0 deletions internal/core/ports/link_repository.go
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import (

"github.com/google/uuid"
"github.com/iden3/go-iden3-core/v2/w3c"
"github.com/iden3/iden3comm/v2/protocol"

"github.com/polygonid/sh-id-platform/internal/core/domain"
"github.com/polygonid/sh-id-platform/internal/db"
@@ -16,4 +17,5 @@ type LinkRepository interface {
GetByID(ctx context.Context, issuerID w3c.DID, id uuid.UUID) (*domain.Link, error)
GetAll(ctx context.Context, issuerDID w3c.DID, status LinkStatus, query *string) ([]domain.Link, error)
Delete(ctx context.Context, id uuid.UUID, issuerDID w3c.DID) error
AddAuthorizationRequest(ctx context.Context, linkID uuid.UUID, issuerDID w3c.DID, authorizationRequest *protocol.AuthorizationRequestMessage) error
}
17 changes: 8 additions & 9 deletions internal/core/ports/link_service.go
Original file line number Diff line number Diff line change
@@ -22,19 +22,19 @@ type CreateQRCodeResponse struct {
DeepLink string
UniversalLink string
QrID uuid.UUID
SessionID string
QrCodeRaw string
}

// LinkStatus is a Link type request. All|Active|Inactive|Exceeded
type LinkStatus string

const (
LinkAll LinkStatus = "all" // LinkAll : All links
LinkActive LinkStatus = "active" // LinkActive : Active links
LinkInactive LinkStatus = "inactive" // LinkInactive : Inactive links
LinkExceeded LinkStatus = "exceeded" // LinkExceeded : Expired links or with more credentials issued than expected
AgentUrl = "%s/v2/agent" // AgentUrl : Agent URL
LinksCallbackURL = "%s/v2/identities/%s/credentials/links/callback?sessionID=%s&linkID=%s" // LinksCallbackURL : Links callback URL
LinkAll LinkStatus = "all" // LinkAll : All links
LinkActive LinkStatus = "active" // LinkActive : Active links
LinkInactive LinkStatus = "inactive" // LinkInactive : Inactive links
LinkExceeded LinkStatus = "exceeded" // LinkExceeded : Expired links or with more credentials issued than expected
AgentUrl = "%s/v2/agent" // AgentUrl : Agent URL
LinksCallbackURL = "%s/v2/identities/%s/credentials/links/callback?linkID=%s" // LinksCallbackURL : Links callback URL
)

// LinkTypeReqFromString constructs a LinkStatus from a string
@@ -61,6 +61,5 @@ type LinkService interface {
GetAll(ctx context.Context, issuerDID w3c.DID, status LinkStatus, query *string) ([]domain.Link, error)
CreateQRCode(ctx context.Context, issuerDID w3c.DID, linkID uuid.UUID, serverURL string) (*CreateQRCodeResponse, error)
IssueOrFetchClaim(ctx context.Context, issuerDID w3c.DID, userDID w3c.DID, linkID uuid.UUID, hostURL string) (*protocol.CredentialsOfferMessage, error)
ProcessCallBack(ctx context.Context, message string, sessionID uuid.UUID, linkID uuid.UUID, hostURL string) (*protocol.CredentialsOfferMessage, error)
GetQRCode(ctx context.Context, sessionID uuid.UUID, issuerID w3c.DID, linkID uuid.UUID) (*GetQRCodeResponse, error)
ProcessCallBack(ctx context.Context, issuerDID w3c.DID, message string, linkID uuid.UUID, hostURL string) (*protocol.CredentialsOfferMessage, error)
}
12 changes: 10 additions & 2 deletions internal/core/ports/qrstore_service.go
Original file line number Diff line number Diff line change
@@ -5,20 +5,28 @@ import (
"time"

"github.com/google/uuid"
"github.com/iden3/go-iden3-core/v2/w3c"
)

const (
// QRStoreUrl is the URL to the QR store service
QRStoreUrl = "iden3comm://?request_uri=%s/v2/qr-store?id=%s"

// QRStoreUrlWithDID is the URL to the QR store service with the issuer DID
QRStoreUrlWithDID = "iden3comm://?request_uri=%s/v2/qr-store?id=%s&issuer=%s"

// UniversalLinkURL - is the URL to the Universal Link
UniversalLinkURL = "%s#request_uri=%s/v2/qr-store?id=%s"

// UniversalLinkURLWithDID - is the URL to the Universal Link with the issuer DID
UniversalLinkURLWithDID = "%s#request_uri=%s/v2/qr-store?id=%s&issuer=%s"
)

// QrStoreService is the interface that provides methods to store and retrieve the body of QR codes and to provide support
// to the QR url shortener functionality.
type QrStoreService interface {
Find(ctx context.Context, id uuid.UUID) ([]byte, error)
Store(ctx context.Context, qrCode []byte, ttl time.Duration) (uuid.UUID, error)
ToDeepLink(hostURL string, id uuid.UUID) string
ToUniversalLink(ULinkBaseUrl string, hostURL string, id uuid.UUID) string
ToDeepLink(hostURL string, id uuid.UUID, issuerDID *w3c.DID) string
ToUniversalLink(ULinkBaseUrl string, hostURL string, id uuid.UUID, issuerDID *w3c.DID) string
}
4 changes: 0 additions & 4 deletions internal/core/ports/session_repository.go
Original file line number Diff line number Diff line change
@@ -4,14 +4,10 @@ import (
"context"

"github.com/iden3/iden3comm/v2/protocol"

link_state "github.com/polygonid/sh-id-platform/pkg/link"
)

// SessionRepository defines the interface for managing sessions
type SessionRepository interface {
Get(ctx context.Context, key string) (protocol.AuthorizationRequestMessage, error)
Set(ctx context.Context, key string, value protocol.AuthorizationRequestMessage) error
SetLink(ctx context.Context, key string, value link_state.State) error
GetLink(ctx context.Context, key string) (link_state.State, error)
}
4 changes: 2 additions & 2 deletions internal/core/services/claims.go
Original file line number Diff line number Diff line change
@@ -372,8 +372,8 @@ func (c *claim) GetCredentialQrCode(ctx context.Context, issID *w3c.DID, id uuid
return nil, err
}
return &ports.GetCredentialQrCodeResponse{
DeepLink: c.qrService.ToDeepLink(hostURL, qrID),
UniversalLink: c.qrService.ToUniversalLink(c.cfg.BaseUrl, hostURL, qrID),
DeepLink: c.qrService.ToDeepLink(hostURL, qrID, nil),
UniversalLink: c.qrService.ToUniversalLink(c.cfg.BaseUrl, hostURL, qrID, nil),
QrRaw: string(raw),
SchemaType: getCredentialType(*claim),
QrID: qrID,
25 changes: 15 additions & 10 deletions internal/core/services/identity.go
Original file line number Diff line number Diff line change
@@ -472,13 +472,7 @@ func (i *identity) UpdateIdentityState(ctx context.Context, state *domain.Identi
return err
}

func (i *identity) Authenticate(ctx context.Context, message string, sessionID uuid.UUID, serverURL string) (*protocol.AuthorizationResponseMessage, error) {
authReq, err := i.sessionManager.Get(ctx, sessionID.String())
if err != nil {
log.Warn(ctx, "authentication session not found")
return nil, err
}

func (i *identity) AuthenticateWithRequest(ctx context.Context, sessionID *uuid.UUID, authReq protocol.AuthorizationRequestMessage, message string, serverURL string) (*protocol.AuthorizationResponseMessage, error) {
arm, err := i.verifier.FullVerify(ctx, message, authReq, pubsignals.WithAcceptedStateTransitionDelay(transitionDelay))
if err != nil {
log.Error(ctx, "authentication failed", "err", err)
@@ -522,7 +516,10 @@ func (i *identity) Authenticate(ctx context.Context, message string, sessionID u
return err
}

return i.connectionsRepository.SaveUserAuthentication(ctx, i.storage.Pgx, connID, sessionID, conn.CreatedAt)
if sessionID == nil {
sessionID = common.ToPointer(uuid.New())
}
return i.connectionsRepository.SaveUserAuthentication(ctx, i.storage.Pgx, connID, *sessionID, conn.CreatedAt)
}); err != nil {
return nil, err
}
@@ -533,10 +530,18 @@ func (i *identity) Authenticate(ctx context.Context, message string, sessionID u
log.Error(ctx, "sending connection notification", "err", err.Error(), "connection", connID)
}
}

return arm, nil
}

func (i *identity) Authenticate(ctx context.Context, message string, sessionID uuid.UUID, serverURL string) (*protocol.AuthorizationResponseMessage, error) {
authReq, err := i.sessionManager.Get(ctx, sessionID.String())
if err != nil {
log.Warn(ctx, "authentication session not found")
return nil, err
}
return i.AuthenticateWithRequest(ctx, &sessionID, authReq, message, serverURL)
}

func (i *identity) CreateAuthenticationQRCode(ctx context.Context, serverURL string, issuerDID w3c.DID) (*ports.CreateAuthenticationQRCodeResponse, error) {
sessionID := uuid.New()
reqID := uuid.New().String()
@@ -566,7 +571,7 @@ func (i *identity) CreateAuthenticationQRCode(ctx context.Context, serverURL str
return nil, err
}
return &ports.CreateAuthenticationQRCodeResponse{
QRCodeURL: i.qrService.ToDeepLink(serverURL, linkID),
QRCodeURL: i.qrService.ToDeepLink(serverURL, linkID, nil),
SessionID: sessionID,
QrID: linkID,
}, nil
102 changes: 49 additions & 53 deletions internal/core/services/link.go
Original file line number Diff line number Diff line change
@@ -23,7 +23,6 @@ import (
"github.com/polygonid/sh-id-platform/internal/loader"
"github.com/polygonid/sh-id-platform/internal/log"
"github.com/polygonid/sh-id-platform/internal/repositories"
linkState "github.com/polygonid/sh-id-platform/pkg/link"
"github.com/polygonid/sh-id-platform/pkg/network"
"github.com/polygonid/sh-id-platform/pkg/notifications"
"github.com/polygonid/sh-id-platform/pkg/pubsub"
@@ -166,6 +165,7 @@ func (ls *Link) Delete(ctx context.Context, id uuid.UUID, did w3c.DID) error {
func (ls *Link) CreateQRCode(ctx context.Context, issuerDID w3c.DID, linkID uuid.UUID, serverURL string) (*ports.CreateQRCodeResponse, error) {
link, err := ls.GetByID(ctx, issuerDID, linkID)
if err != nil {
log.Error(ctx, "cannot fetch the link", "err", err)
return nil, err
}

@@ -174,42 +174,45 @@ func (ls *Link) CreateQRCode(ctx context.Context, issuerDID w3c.DID, linkID uuid
return nil, err
}

sessionID := uuid.New().String()
reqID := uuid.New().String()
qrCode := &protocol.AuthorizationRequestMessage{
From: issuerDID.String(),
ID: reqID,
ThreadID: reqID,
Typ: packers.MediaTypePlainMessage,
Type: protocol.AuthorizationRequestMessageType,
Body: protocol.AuthorizationRequestMessageBody{
CallbackURL: fmt.Sprintf(ports.LinksCallbackURL, serverURL, issuerDID.String(), sessionID, linkID.String()),
Reason: authReason,
Scope: make([]protocol.ZeroKnowledgeProofRequest, 0),
},
}

err = ls.sessionManager.Set(ctx, sessionID, *qrCode)
if err != nil {
return nil, err
}

raw, err := json.Marshal(qrCode)
if err != nil {
return nil, err
}
var authorizationRequestMessage *protocol.AuthorizationRequestMessage
var raw []byte
if link.AuthorizationRequestMessage == nil {
reqID := uuid.New().String()
authorizationRequestMessage = &protocol.AuthorizationRequestMessage{
From: issuerDID.String(),
ID: reqID,
ThreadID: reqID,
Typ: packers.MediaTypePlainMessage,
Type: protocol.AuthorizationRequestMessageType,
Body: protocol.AuthorizationRequestMessageBody{
CallbackURL: fmt.Sprintf(ports.LinksCallbackURL, serverURL, issuerDID.String(), linkID.String()),
Reason: authReason,
Scope: make([]protocol.ZeroKnowledgeProofRequest, 0),
},
}
if err := ls.linkRepository.AddAuthorizationRequest(ctx, linkID, issuerDID, authorizationRequestMessage); err != nil {
log.Error(ctx, "cannot add the authorization request", "err", err)
return nil, err
}
raw, err = json.Marshal(authorizationRequestMessage)
if err != nil {
log.Error(ctx, "cannot marshal the authorization", "err", err)
}
} else {
if err := json.Unmarshal(link.AuthorizationRequestMessage.Bytes, &authorizationRequestMessage); err != nil {
log.Error(ctx, "cannot unmarshal the authorization", "err", err)
return nil, err
}
raw = link.AuthorizationRequestMessage.Bytes

id, err := ls.qrService.Store(ctx, raw, DefaultQRBodyTTL)
if err != nil {
return nil, err
}

return &ports.CreateQRCodeResponse{
SessionID: sessionID,
DeepLink: ls.qrService.ToDeepLink(serverURL, id),
UniversalLink: ls.qrService.ToUniversalLink(ls.cfg.BaseUrl, serverURL, id),
QrID: id,
DeepLink: ls.qrService.ToDeepLink(serverURL, linkID, &issuerDID),
UniversalLink: ls.qrService.ToUniversalLink(ls.cfg.BaseUrl, serverURL, link.ID, &issuerDID),
QrID: link.ID,
Link: link,
QrCodeRaw: string(raw),
}, nil
}

@@ -313,8 +316,20 @@ func (ls *Link) IssueOrFetchClaim(ctx context.Context, issuerDID w3c.DID, userDI
}

// ProcessCallBack - process the callback.
func (ls *Link) ProcessCallBack(ctx context.Context, message string, sessionID uuid.UUID, linkID uuid.UUID, hostURL string) (*protocol.CredentialsOfferMessage, error) {
arm, err := ls.identityService.Authenticate(ctx, message, sessionID, hostURL)
func (ls *Link) ProcessCallBack(ctx context.Context, issuerID w3c.DID, message string, linkID uuid.UUID, hostURL string) (*protocol.CredentialsOfferMessage, error) {
link, err := ls.linkRepository.GetByID(ctx, issuerID, linkID)
if err != nil {
log.Error(ctx, "error fetching the link from the database", "err", err)
return nil, err
}

var authenticationRequest protocol.AuthorizationRequestMessage
if err := json.Unmarshal(link.AuthorizationRequestMessage.Bytes, &authenticationRequest); err != nil {
log.Error(ctx, "error unmarshaling the authorization request", "err", err)
return nil, err
}

arm, err := ls.identityService.AuthenticateWithRequest(ctx, nil, authenticationRequest, message, hostURL)
if err != nil {
log.Error(ctx, "error authenticating", "err", err.Error())
return nil, err
@@ -340,25 +355,6 @@ func (ls *Link) ProcessCallBack(ctx context.Context, message string, sessionID u
return offer, nil
}

// GetQRCode - return the link qr code.
func (ls *Link) GetQRCode(ctx context.Context, sessionID uuid.UUID, issuerID w3c.DID, linkID uuid.UUID) (*ports.GetQRCodeResponse, error) {
link, err := ls.GetByID(ctx, issuerID, linkID)
if err != nil {
log.Error(ctx, "error fetching the link from the database", "err", err)
return nil, err
}

linkStateInCache, err := ls.sessionManager.GetLink(ctx, linkState.CredentialStateCacheKey(linkID.String(), sessionID.String()))
if err != nil {
log.Error(ctx, "error fetching the link state from the cache", "err", err)
return nil, err
}
return &ports.GetQRCodeResponse{
State: &linkStateInCache,
Link: link,
}, nil
}

func (ls *Link) validate(ctx context.Context, link *domain.Link) error {
if link.ValidUntil != nil && time.Now().UTC().After(*link.ValidUntil) {
log.Debug(ctx, "cannot issue a credential for an expired link")
12 changes: 10 additions & 2 deletions internal/core/services/qrstore.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import (
"time"

"github.com/google/uuid"
"github.com/iden3/go-iden3-core/v2/w3c"

"github.com/polygonid/sh-id-platform/internal/core/ports"
"github.com/polygonid/sh-id-platform/internal/log"
@@ -60,12 +61,19 @@ func (s *QrStoreService) Store(ctx context.Context, qrCode []byte, ttl time.Dura
}

// ToDeepLink constructs a deeplink that will be used to get the body of a QR code.
func (s *QrStoreService) ToDeepLink(hostURL string, id uuid.UUID) string {
func (s *QrStoreService) ToDeepLink(hostURL string, id uuid.UUID, issuerDID *w3c.DID) string {
if issuerDID != nil {
return fmt.Sprintf(ports.QRStoreUrlWithDID, hostURL, id.String(), issuerDID.String())
}

return fmt.Sprintf(ports.QRStoreUrl, hostURL, id.String())
}

// ToUniversalLink constructs a universal link
func (s *QrStoreService) ToUniversalLink(uLinkBaseUrl string, hostURL string, id uuid.UUID) string {
func (s *QrStoreService) ToUniversalLink(uLinkBaseUrl string, hostURL string, id uuid.UUID, issuerDID *w3c.DID) string {
if issuerDID != nil {
return fmt.Sprintf(ports.UniversalLinkURLWithDID, uLinkBaseUrl, hostURL, id.String(), issuerDID.String())
}
return fmt.Sprintf(ports.UniversalLinkURL, uLinkBaseUrl, hostURL, id.String())
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

-- +goose Up
-- +goose StatementBegin
ALTER TABLE links
ADD COLUMN authorization_request_message jsonb NULL;
-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
ALTER TABLE links
DROP COLUMN authorization_request_message;
-- +goose StatementEnd
9 changes: 9 additions & 0 deletions internal/repositories/link.go
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ import (

"github.com/google/uuid"
"github.com/iden3/go-iden3-core/v2/w3c"
"github.com/iden3/iden3comm/v2/protocol"
"github.com/jackc/pgtype"
"github.com/jackc/pgx/v4"

@@ -73,6 +74,7 @@ SELECT links.id,
links.refresh_service,
links.display_method,
count(claims.id) as issued_claims,
links.authorization_request_message,
schemas.id as schema_id,
schemas.issuer_id as schema_issuer_id,
schemas.url,
@@ -104,6 +106,7 @@ GROUP BY links.id, schemas.id
&link.RefreshService,
&link.DisplayMethod,
&link.IssuedClaims,
&link.AuthorizationRequestMessage,
&s.ID,
&s.IssuerID,
&s.URL,
@@ -251,3 +254,9 @@ func (l link) Delete(ctx context.Context, id uuid.UUID, issuerDID w3c.DID) error
}
return nil
}

func (l link) AddAuthorizationRequest(ctx context.Context, linkID uuid.UUID, issuerDID w3c.DID, authorizationRequest *protocol.AuthorizationRequestMessage) error {
const sql = `UPDATE links SET authorization_request_message = $1 WHERE id = $2 AND issuer_id = $3`
_, err := l.conn.Pgx.Exec(ctx, sql, authorizationRequest, linkID, issuerDID.String())
return err
}
15 changes: 0 additions & 15 deletions internal/repositories/session.go
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ import (

"github.com/polygonid/sh-id-platform/internal/core/ports"
"github.com/polygonid/sh-id-platform/pkg/cache"
link_state "github.com/polygonid/sh-id-platform/pkg/link"
)

const (
@@ -40,17 +39,3 @@ func (c *cached) Get(ctx context.Context, key string) (protocol.AuthorizationReq
func (c *cached) Set(ctx context.Context, key string, value protocol.AuthorizationRequestMessage) error {
return c.cache.Set(ctx, key, value, defaultTTL)
}

// SetLink - stores the given session information
func (c *cached) SetLink(ctx context.Context, key string, value link_state.State) error {
return c.cache.Set(ctx, key, value, defaultTTL)
}

func (c *cached) GetLink(ctx context.Context, key string) (link_state.State, error) {
var message link_state.State
found := c.cache.Get(ctx, key, &message)
if !found {
return message, fmt.Errorf("link state not found")
}
return message, nil
}

0 comments on commit 3fcd836

Please sign in to comment.