diff --git a/routes/codeFlowJwtRoutes.js b/routes/codeFlowJwtRoutes.js new file mode 100644 index 0000000..0751cd7 --- /dev/null +++ b/routes/codeFlowJwtRoutes.js @@ -0,0 +1,185 @@ +import express from "express"; +import fs from "fs"; +import { v4 as uuidv4 } from "uuid"; +import { generateNonce, buildVpRequestJwt } from "../utils/cryptoUtils.js"; + +import { getAuthCodeSessions } from "../services/cacheService.js"; +import qr from "qr-image"; +import imageDataURI from "image-data-uri"; +import { streamToBuffer } from "@jorgeferrero/stream-to-buffer"; + +const codeFlowRouter = express.Router(); + +const serverURL = process.env.SERVER_URL || "http://localhost:3000"; + +const privateKey = fs.readFileSync("./private-key.pem", "utf-8"); +const publicKeyPem = fs.readFileSync("./public-key.pem", "utf-8"); + +// auth code flow +codeFlowRouter.get(["/offer-code"], async (req, res) => { + const uuid = req.query.sessionId ? req.query.sessionId : uuidv4(); + const codeSessions = getAuthCodeSessions(); + codeSessions.sessions.push(uuid); + codeSessions.results.push({ sessionId: uuid, status: "pending" }); + // console.log("active sessions"); + // console.log(issuanceResults); + let credentialOffer = `openid-credential-offer://?credential_offer_uri=${serverURL}/credential-offer-code/${uuid}`; + + let code = qr.image(credentialOffer, { + type: "png", + ec_level: "H", + size: 10, + margin: 10, + }); + let mediaType = "PNG"; + let encodedQR = imageDataURI.encode(await streamToBuffer(code), mediaType); + res.json({ + qr: encodedQR, + deepLink: credentialOffer, + sessionId: uuid, + }); +}); + +// auth code-flow request +codeFlowRouter.get(["/credential-offer-code/:id"], (req, res) => { + res.json({ + credential_issuer: serverURL, + credentials: ["VerifiablePortableDocumentA2"], + grants: { + authorization_code: { + issuer_state: req.params.id, + }, + }, + }); +}); + +codeFlowRouter.get("/authorize", async (req, res) => { + const responseType = req.query.response_type; + const scope = req.query.scope; + const issuerState = decodeURIComponent(req.query.issuer_state); // This can be associated with the ITB session + const state = req.query.state; + const clientId = decodeURIComponent(req.query.client_id); //DID of the holder requesting the credential + const authorizationDetails = JSON.parse( + decodeURIComponent(req.query.authorization_details) //TODO this contains the credentials requested + ); + const redirectUri = decodeURIComponent(req.query.redirect_uri); + const nonce = req.query.nonce; + const codeChallenge = decodeURIComponent(req.query.code_challenge); + const codeChallengeMethod = req.query.code_challenge_method; //this should equal to S256 + + const clientMetadata = JSON.parse( + decodeURIComponent(req.query.client_metadata) + ); + //validations + let errors = []; + if (authorizationDetails.credential_definition) { + console.log( + `credential ${authorizationDetails.credential_definition.type} was requested` + ); + } else { + if (authorizationDetails.types) { + //EBSI style + console.log(`credential ${authorizationDetails.types} was requested`); + } else { + //errors.push("no credentials requested"); + console.log(`no credentials requested`); + } + } + + if (responseType !== "code") { + errors.push("Invalid response_type"); + } + if (!scope.includes("openid")) { + errors.push("Invalid scope"); + } + + // If validations pass, redirect with a 302 Found response + const authorizationCode = null; //"SplxlOBeZQQYbYS6WxSbIA"; + const codeSessions = getAuthCodeSessions(); + codeSessions.requests.push({ + challenge: codeChallenge, + method: codeChallengeMethod, + sessionId: authorizationCode, + issuerState: issuerState, + state: state, + }); + codeSessions.results.push({ + sessionId: authorizationCode, + issuerState: issuerState, + state: state, + status: "pending", + }); + codeSessions.walletSessions.push(state); // push state as send by wallet + codeSessions.sessions.push(issuerState); + + // for normal response not requesting VP from wallet + //const redirectUrl = `${redirectUri}?code=${authorizationCode}&state=${state}`; + + //5.1.5. Dynamic Credential Request https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-12.html#name-successful-authorization-re + const vpRequestJWT = buildVpRequestJwt( + state, + nonce, + clientId, + "response_uri", + null, + "jwk", + serverURL, + privateKey + ); + const redirectUrl = `http://localhost:8080?state=${state}&client_id=${clientId}&redirect_uri=${serverURL}/direct_post_vci&response_type=id_token&response_mode=direct_post&scope=openid&nonce=${nonce}&request=${vpRequestJWT}`; + + if (errors.length > 0) { + console.error("Validation errors:", errors); + let error_description = ""; + errors.forEach((element) => { + error_description += element + " "; + }); + const encodedErrorDescription = encodeURIComponent( + error_description.trim() + ); + const errorRedirectUrl = `${redirectUri}?error=invalid_request&error_description=${encodedErrorDescription}`; + //TODO mark the codeFlowSession as failed + return res.redirect(302, errorRedirectUrl); + } else { + return res.redirect(302, redirectUrl); + } +}); + +codeFlowRouter.post("/direct_post_vci", async (req, res) => { + console.log("direct_post VP for VCI is below!"); + let state = req.body["state"]; + let jwt = req.body["id_token"]; + if (jwt) { + const codeSessions = getAuthCodeSessions(); + const authorizationCode = generateNonce(16); + updateIssuerStateWithAuthCode( + authorizationCode, + state, + codeSessions.walletSessions, + codeSessions.results, + codeSessions.requests + ); + const redirectUrl = `http://localhost:8080?code=${authorizationCode}&state=${state}`; + return res.redirect(302, redirectUrl); + } else { + return res.sendStatus(500); + } +}); + +function updateIssuerStateWithAuthCode( + code, + walletState, + walletSessions, + codeFlowRequestsResults, + codeFlowRequests +) { + let index = walletSessions.indexOf(walletState); + if (index >= 0) { + codeFlowRequestsResults[index].sessionId = code; + codeFlowRequests[index].sessionId = code; + } else { + console.log("issuer state will not be updated"); + } +} + +export default codeFlowRouter; diff --git a/routes/codeFlowSdJwtRoutes.js b/routes/codeFlowSdJwtRoutes.js new file mode 100644 index 0000000..8f5556e --- /dev/null +++ b/routes/codeFlowSdJwtRoutes.js @@ -0,0 +1,52 @@ +import express from "express"; +import fs from "fs"; +import { v4 as uuidv4 } from "uuid"; +import { getAuthCodeSessions } from "../services/cacheService.js"; + +import qr from "qr-image"; +import imageDataURI from "image-data-uri"; +import { streamToBuffer } from "@jorgeferrero/stream-to-buffer"; + +const codeFlowRouterSDJWT = express.Router(); + +const serverURL = process.env.SERVER_URL || "http://localhost:3000"; + + + +// auth code flow +codeFlowRouterSDJWT.get(["/offer-code-sd-jwt"], async (req, res) => { + const uuid = req.query.sessionId ? req.query.sessionId : uuidv4(); + const codeSessions = getAuthCodeSessions(); + codeSessions.sessions.push(uuid); + codeSessions.results.push({ sessionId: uuid, status: "pending" }); + let credentialOffer = `openid-credential-offer://?credential_offer_uri=${serverURL}/credential-offer-code-sd-jwt/${uuid}`; + + let code = qr.image(credentialOffer, { + type: "png", + ec_level: "H", + size: 10, + margin: 10, + }); + let mediaType = "PNG"; + let encodedQR = imageDataURI.encode(await streamToBuffer(code), mediaType); + res.json({ + qr: encodedQR, + deepLink: credentialOffer, + sessionId: uuid, + }); +}); + +// auth code-flow request +codeFlowRouterSDJWT.get(["/credential-offer-code-sd-jwt/:id"], (req, res) => { + res.json({ + credential_issuer: serverURL, + credentials: ["VerifiablePortableDocumentA1"], + grants: { + authorization_code: { + issuer_state: req.params.id, + }, + }, + }); +}); + +export default codeFlowRouterSDJWT; diff --git a/routes/metadataroutes.js b/routes/metadataroutes.js new file mode 100644 index 0000000..1070f47 --- /dev/null +++ b/routes/metadataroutes.js @@ -0,0 +1,58 @@ +import express from "express"; +import fs from "fs"; +import { pemToJWK } from "../utils/cryptoUtils.js"; +const metadataRouter = express.Router(); + +const serverURL = process.env.SERVER_URL || "http://localhost:3000"; + +const privateKey = fs.readFileSync("./private-key.pem", "utf-8"); +const publicKeyPem = fs.readFileSync("./public-key.pem", "utf-8"); + +const issuerConfig = JSON.parse( + fs.readFileSync("./data/issuer-config.json", "utf-8") +); +const oauthConfig = JSON.parse( + fs.readFileSync("./data/oauth-config.json", "utf-8") +); + +const jwks = pemToJWK(publicKeyPem, "public"); + +metadataRouter.get( + "/.well-known/openid-credential-issuer", + async (req, res) => { + issuerConfig.credential_issuer = serverURL; + issuerConfig.authorization_server = serverURL; + issuerConfig.credential_endpoint = serverURL + "/credential"; + issuerConfig.deferred_credential_endpoint = + serverURL + "/credential_deferred"; + + res.type("application/json").send(issuerConfig); + } +); + +metadataRouter.get( + [ + "/.well-known/oauth-authorization-server", + "/.well-known/openid-configuration", + "/oauth-authorization-server/rfc-issuer", //this is required in case the issuer is behind a reverse proxy: see https://www.rfc-editor.org/rfc/rfc8414.html + ], + async (req, res) => { + oauthConfig.issuer = serverURL; + oauthConfig.authorization_endpoint = serverURL + "/authorize"; + oauthConfig.token_endpoint = serverURL + "/token_endpoint"; + oauthConfig.jwks_uri = serverURL + "/jwks"; + res.type("application/json").send(oauthConfig); + } +); + +metadataRouter.get(["/", "/jwks"], (req, res) => { + res.json({ + keys: [ + { ...jwks, kid: `aegean#authentication-key`, use: "sig" }, + { ...jwks, kid: `aegean#authentication-key`, use: "keyAgreement" }, //key to encrypt the sd-jwt response]) + ], + }); +}); + + +export default metadataRouter; \ No newline at end of file diff --git a/routes/routes.js b/routes/routes.js index c0c403d..88666a1 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -5,13 +5,18 @@ import { pemToJWK, generateNonce, base64UrlEncodeSha256, - buildVpRequestJwt, } from "../utils/cryptoUtils.js"; import { buildAccessToken, generateRefreshToken, buildIdToken, } from "../utils/tokenUtils.js"; + +import { + getAuthCodeSessions, + getPreCodeSessions, +} from "../services/cacheService.js"; + import { SDJwtVcInstance } from "@sd-jwt/sd-jwt-vc"; import { createSignerVerifier, @@ -34,65 +39,12 @@ const publicKeyPem = fs.readFileSync("./public-key.pem", "utf-8"); console.log("privateKey"); console.log(privateKey); -const issuerConfig = JSON.parse( - fs.readFileSync("./data/issuer-config.json", "utf-8") -); -const oauthConfig = JSON.parse( - fs.readFileSync("./data/oauth-config.json", "utf-8") -); - -const jwks = pemToJWK(publicKeyPem, "public"); - -//TODO move this into a service that caches these (e.g via redis or something) -let sessions = []; -let issuanceResults = []; -let walletCodeSessions = []; -let issuerCodeSessions = []; -let codeFlowRequests = []; -let codeFlowRequestsResults = []; - -router.get("/.well-known/openid-credential-issuer", async (req, res) => { - // console.log("1 ROUTE /.well-known/openid-credential-issuer CALLED!!!!!!"); - // issuerConfig.authorization_servers = [serverURL]; - issuerConfig.credential_issuer = serverURL; - // issuerConfig.authorization_servers = [serverURL]; - issuerConfig.authorization_server = serverURL; - issuerConfig.credential_endpoint = serverURL + "/credential"; - issuerConfig.deferred_credential_endpoint = - serverURL + "/credential_deferred"; - - res.type("application/json").send(issuerConfig); -}); - -router.get( - [ - "/.well-known/oauth-authorization-server", - "/.well-known/openid-configuration", - "/oauth-authorization-server/rfc-issuer", //this is required in case the issuer is behind a reverse proxy: see https://www.rfc-editor.org/rfc/rfc8414.html - ], - async (req, res) => { - oauthConfig.issuer = serverURL; - oauthConfig.authorization_endpoint = serverURL + "/authorize"; - oauthConfig.token_endpoint = serverURL + "/token_endpoint"; - oauthConfig.jwks_uri = serverURL + "/jwks"; - res.type("application/json").send(oauthConfig); - } -); - -router.get(["/", "/jwks"], (req, res) => { - res.json({ - keys: [ - { ...jwks, kid: `aegean#authentication-key`, use: "sig" }, - { ...jwks, kid: `aegean#authentication-key`, use: "keyAgreement" }, //key to encrypt the sd-jwt response]) - ], - }); -}); - ///pre-auth flow router.get(["/offer"], async (req, res) => { const uuid = req.query.sessionId ? req.query.sessionId : uuidv4(); - sessions.push(uuid); - issuanceResults.push({ sessionId: uuid, status: "pending" }); + const preSessions = getPreCodeSessions(); + preSessions.sessions.push(uuid); + preSessions.results.push({ sessionId: uuid, status: "pending" }); // console.log("active sessions"); // console.log(issuanceResults); let credentialOffer = `openid-credential-offer://?credential_offer_uri=${serverURL}/credential-offer/${uuid}`; //OfferUUID @@ -112,30 +64,6 @@ router.get(["/offer"], async (req, res) => { }); }); -// auth code flow -router.get(["/offer-code"], async (req, res) => { - const uuid = req.query.sessionId ? req.query.sessionId : uuidv4(); - sessions.push(uuid); - issuanceResults.push({ sessionId: uuid, status: "pending" }); - console.log("active sessions"); - console.log(issuanceResults); //TODO associate this with a different "cache" - let credentialOffer = `openid-credential-offer://?credential_offer_uri=${serverURL}/credential-offer-code/${uuid}`; - - let code = qr.image(credentialOffer, { - type: "png", - ec_level: "H", - size: 10, - margin: 10, - }); - let mediaType = "PNG"; - let encodedQR = imageDataURI.encode(await streamToBuffer(code), mediaType); - res.json({ - qr: encodedQR, - deepLink: credentialOffer, - sessionId: uuid, - }); -}); - //pre-auth flow request router.get(["/credential-offer/:id"], (req, res) => { res.json({ @@ -150,146 +78,6 @@ router.get(["/credential-offer/:id"], (req, res) => { }); }); -// auth code-flow request -router.get(["/credential-offer-code/:id"], (req, res) => { - res.json({ - credential_issuer: serverURL, - credentials: ["VerifiablePortableDocumentA2"], - grants: { - authorization_code: { - issuer_state: req.params.id, - }, - }, - }); -}); - -router.get("/authorize", async (req, res) => { - const responseType = req.query.response_type; - const scope = req.query.scope; - const issuerState = decodeURIComponent(req.query.issuer_state); // This can be associated with the ITB session - const state = req.query.state; - const clientId = decodeURIComponent(req.query.client_id); //DID of the holder requesting the credential - const authorizationDetails = JSON.parse( - decodeURIComponent(req.query.authorization_details) //TODO this contains the credentials requested - ); - const redirectUri = decodeURIComponent(req.query.redirect_uri); - const nonce = req.query.nonce; - const codeChallenge = decodeURIComponent(req.query.code_challenge); - const codeChallengeMethod = req.query.code_challenge_method; //this should equal to S256 - - const clientMetadata = JSON.parse( - decodeURIComponent(req.query.client_metadata) - ); - //validations - let errors = []; - if (authorizationDetails.credential_definition) { - console.log( - `credential ${authorizationDetails.credential_definition.type} was requested` - ); - } else { - if (authorizationDetails.types) { - //EBSI style - console.log(`credential ${authorizationDetails.types} was requested`); - } else { - //errors.push("no credentials requested"); - console.log(`no credentials requested`); - } - } - - if (responseType !== "code") { - errors.push("Invalid response_type"); - } - if (!scope.includes("openid")) { - errors.push("Invalid scope"); - } - - // If validations pass, redirect with a 302 Found response - const authorizationCode = null; //"SplxlOBeZQQYbYS6WxSbIA"; - codeFlowRequests.push({ - challenge: codeChallenge, - method: codeChallengeMethod, - sessionId: authorizationCode, - issuerState: issuerState, - state: state, - }); - codeFlowRequestsResults.push({ - sessionId: authorizationCode, - issuerState: issuerState, - state: state, - status: "pending", - }); - walletCodeSessions.push(state); // push state as send by wallet - issuerCodeSessions.push(issuerState); - - // for normal response not requesting VP from wallet - //const redirectUrl = `${redirectUri}?code=${authorizationCode}&state=${state}`; - - //5.1.5. Dynamic Credential Request https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-12.html#name-successful-authorization-re - const vpRequestJWT = buildVpRequestJwt( - state, - nonce, - clientId, - "response_uri", - null, - "jwk", - serverURL, - privateKey - ); - const redirectUrl = `http://localhost:8080?state=${state}&client_id=${clientId}&redirect_uri=${serverURL}/direct_post_vci&response_type=id_token&response_mode=direct_post&scope=openid&nonce=${nonce}&request=${vpRequestJWT}`; - - if (errors.length > 0) { - console.error("Validation errors:", errors); - let error_description = ""; - errors.forEach((element) => { - error_description += element + " "; - }); - const encodedErrorDescription = encodeURIComponent( - error_description.trim() - ); - const errorRedirectUrl = `${redirectUri}?error=invalid_request&error_description=${encodedErrorDescription}`; - //TODO mark the codeFlowSession as failed - return res.redirect(302, errorRedirectUrl); - } else { - return res.redirect(302, redirectUrl); - } -}); - -router.post("/direct_post_vci", async (req, res) => { - console.log("direct_post VP for VCI is below!"); - let state = req.body["state"]; - let jwt = req.body["id_token"]; - if (jwt) { - const authorizationCode = generateNonce(16); - updateIssuerStateWithAuthCode( - authorizationCode, - state, - walletCodeSessions, - codeFlowRequestsResults, - codeFlowRequests - ); - const redirectUrl = `http://localhost:8080?code=${authorizationCode}&state=${state}`; - return res.redirect(302, redirectUrl); - } else { - return res.sendStatus(500); - } -}); - -function updateIssuerStateWithAuthCode( - code, - walletState, - walletSessions, - codeFlowRequestsResults, - codeFlowRequests -) { - let index = walletSessions.indexOf(walletState); - if (index >= 0) { - codeFlowRequestsResults[index].sessionId = code; - codeFlowRequests[index].sessionId = code; - } else { - console.log("issuer state will not be updated"); - } -} - router.post("/token_endpoint", async (req, res) => { //pre-auth code flow const grantType = req.body.grant_type; @@ -308,21 +96,23 @@ router.post("/token_endpoint", async (req, res) => { if (grantType == "urn:ietf:params:oauth:grant-type:pre-authorized_code") { console.log("pre-auth code flow"); - let index = sessions.indexOf(preAuthorizedCode); + const preSessions = getPreCodeSessions(); + let index = preSessions.sessions.indexOf(preAuthorizedCode); if (index >= 0) { console.log( `credential for session ${preAuthorizedCode} has been issued` ); - issuanceResults[index].status = "success"; - console.log("pre-auth code flow" + issuanceResults[index].status); + preSessions.results[index].status = "success"; + // console.log("pre-auth code flow" + preSessions.results[index].status); } } else { if (grantType == "authorization_code") { + const codeSessions = getAuthCodeSessions(); validatePKCE( - codeFlowRequests, + codeSessions.requests, code, code_verifier, - codeFlowRequestsResults + codeSessions.results ); } } @@ -344,6 +134,7 @@ router.post("/credential", async (req, res) => { const token = authHeader && authHeader.split(" ")[1]; // Split "Bearer" and the token // Accessing the body data const requestBody = req.body; + const format = requestBody.format; //TODO valiate bearer header let decodedWithHeader; let decodedHeaderSubjectDID; @@ -354,100 +145,101 @@ router.post("/credential", async (req, res) => { decodedHeaderSubjectDID = decodedWithHeader.payload.iss; } - // console.log("Token:", token); - // console.log("Request Body:", requestBody); - const { signer, verifier } = await createSignerVerifier( - pemToJWK(privateKey, "private"), - pemToJWK(publicKeyPem, "public") - ); - const sdjwt = new SDJwtVcInstance({ - signer, - verifier, - signAlg: "ES384", - hasher: digest, - hashAlg: "SHA-256", - saltGenerator: generateSalt, - }); - const claims = { - given_name: "John", - last_name: "Doe", - }; - const disclosureFrame = { - _sd: ["given_name", "last_name"], - }; - const credential = await sdjwt.issue( - { - iss: serverURL, - iat: new Date().getTime(), - vct: "VerifiablePortableDocumentA1", - ...claims, - }, - disclosureFrame - ); // console.log(credential); - - //sign as jwt - const payload = { - iss: serverURL, - sub: decodedHeaderSubjectDID || "", - exp: Math.floor(Date.now() / 1000) + 60 * 60, // Token expiration time (1 hour from now) - iat: Math.floor(Date.now() / 1000), // Token issued at time - // nbf: Math.floor(Date.now() / 1000), - jti: "urn:did:1904a925-38bd-4eda-b682-4b5e3ca9d4bc", - vc: { - credentialSubject: { - id: null, - given_name: "John", - last_name: "Doe", + if (format === "jwt_vc") { + //sign as jwt + const payload = { + iss: serverURL, + sub: decodedHeaderSubjectDID || "", + exp: Math.floor(Date.now() / 1000) + 60 * 60, // Token expiration time (1 hour from now) + iat: Math.floor(Date.now() / 1000), // Token issued at time + // nbf: Math.floor(Date.now() / 1000), + jti: "urn:did:1904a925-38bd-4eda-b682-4b5e3ca9d4bc", + vc: { + credentialSubject: { + id: null, + given_name: "John", + last_name: "Doe", + }, + expirationDate: new Date( + (Math.floor(Date.now() / 1000) + 60 * 60) * 1000 + ).toISOString(), + id: "urn:did:1904a925-38bd-4eda-b682-4b5e3ca9d4bc", + issuanceDate: new Date( + Math.floor(Date.now() / 1000) * 1000 + ).toISOString(), + issued: new Date(Math.floor(Date.now() / 1000) * 1000).toISOString(), + issuer: serverURL, + type: ["VerifiablePortableDocumentA2"], + validFrom: new Date(Math.floor(Date.now() / 1000) * 1000).toISOString(), }, - expirationDate: new Date( - (Math.floor(Date.now() / 1000) + 60 * 60) * 1000 - ).toISOString(), - id: "urn:did:1904a925-38bd-4eda-b682-4b5e3ca9d4bc", - issuanceDate: new Date( - Math.floor(Date.now() / 1000) * 1000 - ).toISOString(), - issued: new Date(Math.floor(Date.now() / 1000) * 1000).toISOString(), - issuer: serverURL, - type: ["VerifiablePortableDocumentA2"], - validFrom: new Date(Math.floor(Date.now() / 1000) * 1000).toISOString(), - }, - // Optional claims - }; - - const signOptions = { - algorithm: "ES256", // Specify the signing algorithm - }; - - // Define additional JWT header fields - const additionalHeaders = { - kid: "aegean#authentication-key", - typ: "JWT", - }; - // Sign the token - const idtoken = jwt.sign(payload, privateKey, { - ...signOptions, - header: additionalHeaders, // Include additional headers separately - }); + // Optional claims + }; + + const signOptions = { + algorithm: "ES256", // Specify the signing algorithm + }; + + // Define additional JWT header fields + const additionalHeaders = { + kid: "aegean#authentication-key", + typ: "JWT", + }; + // Sign the token + const idtoken = jwt.sign(payload, privateKey, { + ...signOptions, + header: additionalHeaders, // Include additional headers separately + }); - // console.log(idtoken); + // console.log(idtoken); - /* jwt format */ - res.json({ - format: "jwt_vc", - credential: idtoken, - c_nonce: generateNonce(), - c_nonce_expires_in: 86400, - }); + /* jwt format */ + res.json({ + format: "jwt_vc", + credential: idtoken, + c_nonce: generateNonce(), + c_nonce_expires_in: 86400, + }); + } else { + // console.log("Token:", token); + // console.log("Request Body:", requestBody); + const { signer, verifier } = await createSignerVerifier( + pemToJWK(privateKey, "private"), + pemToJWK(publicKeyPem, "public") + ); + const sdjwt = new SDJwtVcInstance({ + signer, + verifier, + signAlg: "ES384", + hasher: digest, + hashAlg: "SHA-256", + saltGenerator: generateSalt, + }); + const claims = { + given_name: "John", + last_name: "Doe", + }; + const disclosureFrame = { + _sd: ["given_name", "last_name"], + }; + const credential = await sdjwt.issue( + { + iss: serverURL, + iat: new Date().getTime(), + vct: "VerifiablePortableDocumentA1", + ...claims, + }, + disclosureFrame + ); + res.json({ + format: "vc+sd-jwt", + credential: credential, + c_nonce: generateNonce(), + c_nonce_expires_in: 86400, + }); + } - /*sd-jwt formatt */ - /* - res.json({ - format: "vc+sd-jwt", - credential: credential, - c_nonce: generateNonce(), - c_nonce_expires_in: 86400, - });*/ + }); //issuerConfig.credential_endpoint = serverURL + "/credential"; @@ -456,15 +248,20 @@ router.get(["/issueStatus"], (req, res) => { let sessionId = req.query.sessionId; // walletCodeSessions,codeFlowRequestsResults,codeFlowRequests - + const preSessions = getPreCodeSessions(); + const codeSessions = getAuthCodeSessions(); let result = - checkIfExistsIssuanceStatus(sessionId, sessions, issuanceResults) || checkIfExistsIssuanceStatus( sessionId, - issuerCodeSessions, - codeFlowRequestsResults, - walletCodeSessions, - codeFlowRequests + preSessions.sessions, + preSessions.results + ) || + checkIfExistsIssuanceStatus( + sessionId, + codeSessions.sessions, + codeSessions.results, + codeSessions.walletSessions, + codeSessions.requests ); if (result) { res.json({ @@ -493,11 +290,11 @@ function checkIfExistsIssuanceStatus( console.log(index); if (index >= 0) { let status = sessionResults[index].status; - console.log(`sending status ${status} for session ${sessionId}`); - console.log(`new sessions`); - console.log(sessions); - console.log("new session statuses"); - console.log(sessionResults); + // console.log(`sending status ${status} for session ${sessionId}`); + // console.log(`new sessions`); + // console.log(sessions); + // console.log("new session statuses"); + // console.log(sessionResults); if (status === "success") { sessions.splice(index, 1); sessionResults.splice(index, 1); diff --git a/server.js b/server.js index 90bd468..cc7458b 100644 --- a/server.js +++ b/server.js @@ -2,9 +2,10 @@ import express from "express"; import router from "./routes/routes.js"; import verifierRouter from "./routes/verifierRoutes.js"; -import bodyParser from 'body-parser'; // Body parser middleware - - +import metadataRouter from "./routes/metadataroutes.js"; +import codeFlowRouter from "./routes/codeFlowJwtRoutes.js" +import codeFlowRouterSDJWT from "./routes/codeFlowSdJwtRoutes.js" +import bodyParser from "body-parser"; // Body parser middleware const app = express(); const port = 3000; @@ -21,8 +22,11 @@ app.use((req, res, next) => { }); app.use("/", router); app.use("/", verifierRouter); +app.use("/", metadataRouter); +app.use("/", codeFlowRouter); +app.use("/", codeFlowRouterSDJWT); // Start the server app.listen(port, () => { - console.log(`Server is running on http://localhost:${port}`); - }); \ No newline at end of file + console.log(`Server is running on http://localhost:${port}`); +}); diff --git a/services/cacheService.js b/services/cacheService.js new file mode 100644 index 0000000..5a7b7b3 --- /dev/null +++ b/services/cacheService.js @@ -0,0 +1,25 @@ +let sessions = []; +let issuanceResults = []; + +let walletCodeSessions = []; +let issuerCodeSessions = []; +let codeFlowRequests = []; +let codeFlowRequestsResults = []; + +export function getPreCodeSessions() { + return { + sessions: sessions, + results: issuanceResults, + }; +} + +export function getAuthCodeSessions() { + return { + walletSessions: walletCodeSessions, + sessions: issuerCodeSessions, + requests: codeFlowRequests, + results: codeFlowRequestsResults, + }; +} + +