Skip to content

Commit

Permalink
Use DID instead of username to identify users internally
Browse files Browse the repository at this point in the history
  • Loading branch information
emlun committed Sep 4, 2023
1 parent d84e823 commit 7e0353d
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 121 deletions.
21 changes: 0 additions & 21 deletions src/entities/user.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,26 +143,6 @@ async function getUserByCredentials(username: string, password: string): Promise
}
}

async function getUserByUsername(username: string): Promise<Result<UserEntity, GetUserErr>> {
try {

const res = await AppDataSource.getRepository(UserEntity)
.createQueryBuilder("user")
.where("user.username = :username", { username: username })
.getOne();
if (!res) {
return Err(GetUserErr.NOT_EXISTS);
}

return Ok(res);
}
catch(e) {
console.log(e);
return Err(GetUserErr.DB_ERR)
}
}


async function getAllUsers(): Promise<Result<UserEntity[], GetUserErr>> {
try {

Expand Down Expand Up @@ -207,6 +187,5 @@ export {
getUserByDID,
getUserByCredentials,
UpdateFcmError,
getUserByUsername,
getAllUsers
}
10 changes: 5 additions & 5 deletions src/routers/issuance.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ issuanceRouter.post('/generate/authorization/request', async (req, res) => {
const {
legal_person_did,
} = req.body;
const result = await openidForCredentialIssuanceService.generateAuthorizationRequestURL(req.user.username, null, legal_person_did);
const result = await openidForCredentialIssuanceService.generateAuthorizationRequestURL(req.user.did, null, legal_person_did);
res.send(result);
}
catch(err) {
Expand All @@ -38,7 +38,7 @@ issuanceRouter.post('/generate/authorization/request/with/offer', async (req, re
credential_offer_url,
} = req.body;

const result = await openidForCredentialIssuanceService.generateAuthorizationRequestURL(req.user.username, credential_offer_url, null);
const result = await openidForCredentialIssuanceService.generateAuthorizationRequestURL(req.user.did, credential_offer_url, null);
res.send(result);
}
catch(err) {
Expand All @@ -57,7 +57,7 @@ issuanceRouter.post('/handle/authorization/response', async (req, res) => {
if (!(new URL(authorization_response_url).searchParams.get("code"))) {
return res.status(500).send({});
}
await openidForCredentialIssuanceService.handleAuthorizationResponse(req.user.username, authorization_response_url);
await openidForCredentialIssuanceService.handleAuthorizationResponse(req.user.did, authorization_response_url);
res.send({});
}
catch(err) {
Expand All @@ -72,7 +72,7 @@ issuanceRouter.post('/request/credentials/with/pre_authorized', async (req, res)
user_pin
} = req.body;

await openidForCredentialIssuanceService.requestCredentialsWithPreAuthorizedGrant(req.user.username, user_pin);
await openidForCredentialIssuanceService.requestCredentialsWithPreAuthorizedGrant(req.user.did, user_pin);
res.send({});
}
catch(err) {
Expand All @@ -83,4 +83,4 @@ issuanceRouter.post('/request/credentials/with/pre_authorized', async (req, res)

export {
issuanceRouter
}
}
6 changes: 3 additions & 3 deletions src/routers/presentation.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ presentationRouter.post('/handle/authorization/request', async (req, res) => {
} = req.body;

try{
const outboundRequest = await openidForPresentationService.handleRequest(req.user.username, authorization_request)
const outboundRequest = await openidForPresentationService.handleRequest(req.user.did, authorization_request)
if (outboundRequest.conformantCredentialsMap && outboundRequest.verifierDomainName) {
const { conformantCredentialsMap, verifierDomainName } = outboundRequest;
// convert from map to JSON
Expand Down Expand Up @@ -54,7 +54,7 @@ presentationRouter.post('/generate/authorization/response', async (req, res) =>

const selection = new Map(Object.entries(verifiable_credentials_map)) as Map<string, string>;
try {
const { redirect_to, error } = await openidForPresentationService.sendResponse(req.user.username, selection);
const { redirect_to, error } = await openidForPresentationService.sendResponse(req.user.did, selection);
if (error) {
const errText = `Error generating authorization response: ${error}`;
console.error(errText);
Expand All @@ -74,4 +74,4 @@ presentationRouter.post('/generate/authorization/response', async (req, res) =>

export {
presentationRouter
}
}
2 changes: 1 addition & 1 deletion src/routers/user.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,4 @@ userController.post('/login', async (req: Request, res: Response) => {
// res.send({ publicKeyJwk });
// });

export default userController;
export default userController;
22 changes: 8 additions & 14 deletions src/services/DatabaseKeystoreService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SignJWT, importJWK } from "jose";
import { AdditionalKeystoreParameters, WalletKeystore } from "./interfaces";
import { getUserByUsername } from "../entities/user.entity";
import { getUserByDID } from "../entities/user.entity";
import { SignVerifiablePresentationJWT, WalletKey } from "@gunet/ssi-sdk";
import { randomUUID } from "crypto";
import { verifiablePresentationSchemaURL } from "../util/util";
Expand All @@ -16,9 +16,9 @@ export class DatabaseKeystoreService implements WalletKeystore {

constructor() { }

async createIdToken(username: string, nonce: string, audience: string, additionalParameters: AdditionalKeystoreParameters): Promise<{ id_token: string; }> {
async createIdToken(userDid: string, nonce: string, audience: string, additionalParameters: AdditionalKeystoreParameters): Promise<{ id_token: string; }> {

const user = (await getUserByUsername(username)).unwrap();
const user = (await getUserByDID(userDid)).unwrap();

const keys = JSON.parse(user.keys.toString()) as WalletKey;
const privateKey = await importJWK(keys.privateKey, keys.alg);
Expand All @@ -39,8 +39,8 @@ export class DatabaseKeystoreService implements WalletKeystore {
return { id_token: jws };
}

async signJwtPresentation(username: string, nonce: string, audience: string, verifiableCredentials: any[], additionalParameters: AdditionalKeystoreParameters): Promise<{ vpjwt: string }> {
const user = (await getUserByUsername(username)).unwrap();
async signJwtPresentation(userDid: string, nonce: string, audience: string, verifiableCredentials: any[], additionalParameters: AdditionalKeystoreParameters): Promise<{ vpjwt: string }> {
const user = (await getUserByDID(userDid)).unwrap();
const keys = JSON.parse(user.keys.toString()) as WalletKey;
const privateKey = await importJWK(keys.privateKey, keys.alg);

Expand Down Expand Up @@ -68,9 +68,9 @@ export class DatabaseKeystoreService implements WalletKeystore {
return { vpjwt: jws };
}

async generateOpenid4vciProof(username: string, audience: string, nonce: string, additionalParameters: AdditionalKeystoreParameters): Promise<{ proof_jwt: string }> {
async generateOpenid4vciProof(userDid: string, audience: string, nonce: string, additionalParameters: AdditionalKeystoreParameters): Promise<{ proof_jwt: string }> {

const user = (await getUserByUsername(username)).unwrap();
const user = (await getUserByDID(userDid)).unwrap();

const keys = JSON.parse(user.keys.toString()) as WalletKey;
const privateKey = await importJWK(keys.privateKey, keys.alg);
Expand All @@ -90,11 +90,5 @@ export class DatabaseKeystoreService implements WalletKeystore {
return { proof_jwt: jws };

}
async getIdentifier(username: string): Promise<string> {
const user = (await getUserByUsername(username)).unwrap();
return user.did;
}



}
}
70 changes: 34 additions & 36 deletions src/services/OpenidForCredentialIssuanceService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axios from "axios";
import { LegalPersonEntity, getLegalPersonByDID, getLegalPersonByUrl } from "../entities/LegalPerson.entity";
import { CredentialIssuerMetadata, CredentialResponseSchemaType, CredentialSupportedJwtVcJson, GrantType, OpenidConfiguration, TokenResponseSchemaType, VerifiableCredentialFormat } from "../types/oid4vci";
import config from "../../config";
import { getUserByUsername } from "../entities/user.entity";
import { getUserByDID } from "../entities/user.entity";
import { sendPushNotification } from "../lib/firebase";
import * as _ from 'lodash';
import { generateCodeChallengeFromVerifier, generateCodeVerifier } from "../util/util";
Expand All @@ -17,7 +17,7 @@ import "reflect-metadata";


type IssuanceState = {
username: string; // Before Authorization Req
userDid: string; // Before Authorization Req
legalPerson: LegalPersonEntity; // Before Authorization Req
credentialIssuerMetadata: CredentialIssuerMetadata; // Before Authorization Req
openidConfiguration: OpenidConfiguration; // Before Authorization Req
Expand All @@ -39,24 +39,24 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei
// legalPersonService: LegalPersonService = new LegalPersonService();


// key: username
// key: userDid
public states = new Map<string, IssuanceState>();


// This is a queue of the credentials which are ready
// to be received.
// When a credential is ready to be received, the credential response
// is added for specific fcm token and a notification is sent to the device.
// key: username, value: array of credential responses
// key: userDid, value: array of credential responses
credentialQueue = new Map<string, CredentialResponseSchemaType[]>();

constructor(
@inject(TYPES.WalletKeystore) private walletKeyStore: WalletKeystore,
) { }


async getIssuerState(username: string): Promise<{ issuer_state?: string, error?: Error; }> {
const state = this.states.get(username);
async getIssuerState(userDid: string): Promise<{ issuer_state?: string, error?: Error; }> {
const state = this.states.get(userDid);
if (!state) {
return { issuer_state: null, error: new Error("No state found") };
}
Expand All @@ -83,14 +83,14 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei

/**
*
* @param username
* @param userDid
* @param legalPersonDID
* @returns
* @throws
*/
async generateAuthorizationRequestURL(username: string, credentialOfferURL?: string, legalPersonDID?: string): Promise<{ redirect_to: string }> {
console.log("Username = ", username)
console.log("LP = ", legalPersonDID)
async generateAuthorizationRequestURL(userDid: string, credentialOfferURL?: string, legalPersonDID?: string): Promise<{ redirect_to: string }> {
console.log("generateAuthorizationRequestURL userDid = ", userDid);
console.log("LP = ", legalPersonDID);
let issuerUrlString: string | null = null;
let credential_offer = null;
let issuer_state = null;
Expand All @@ -104,8 +104,6 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei
response_types_supported: [ "vp_token", "id_token" ]
};

const walletDID = await this.walletKeyStore.getIdentifier(username);

let lp: LegalPersonEntity;

if (legalPersonDID) {
Expand Down Expand Up @@ -155,8 +153,8 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei
});

if (credential_offer && credential_offer.grants["urn:ietf:params:oauth:grant-type:pre-authorized_code"]) {
this.states.set(username, {
username: username,
this.states.set(userDid, {
userDid,
credentialIssuerMetadata: credentialIssuerMetadata,
openidConfiguration: authorizationServerConfig,
legalPerson: lp,
Expand All @@ -177,7 +175,7 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei

const authorizationRequestURL = new URL(authorizationServerConfig.authorization_endpoint);
authorizationRequestURL.searchParams.append("scope", "openid");
authorizationRequestURL.searchParams.append("client_id", walletDID);
authorizationRequestURL.searchParams.append("client_id", userDid);

authorizationRequestURL.searchParams.append("redirect_uri", config.walletClientUrl);

Expand All @@ -190,8 +188,8 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei
authorizationRequestURL.searchParams.append("issuer_state", issuer_state);

authorizationRequestURL.searchParams.append("client_metadata", JSON.stringify(client_metadata));
this.states.set(username, {
username: username,
this.states.set(userDid, {
userDid,
authorization_details: authorizationDetails,
credentialIssuerMetadata: credentialIssuerMetadata,
openidConfiguration: authorizationServerConfig,
Expand All @@ -206,15 +204,15 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei



public async requestCredentialsWithPreAuthorizedGrant(username: string, user_pin: string) {
let state = this.states.get(username)
public async requestCredentialsWithPreAuthorizedGrant(userDid: string, user_pin: string) {
let state = this.states.get(userDid)
state = { ...state, user_pin: user_pin };
this.states.set(username, state); // save state with pin
this.states.set(userDid, state); // save state with pin

this.tokenRequest(state).then(tokenResponse => {
state = { ...state, tokenResponse }
this.states.set(username, state);
this.credentialRequests(username, state).catch(e => {
this.states.set(userDid, state);
this.credentialRequests(userDid, state).catch(e => {
console.error("Credential requests failed with error : ", e)
});
})
Expand All @@ -225,20 +223,20 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei
* @param authorizationResponseURL
* @throws
*/
public async handleAuthorizationResponse(username: string, authorizationResponseURL: string): Promise<void> {
public async handleAuthorizationResponse(userDid: string, authorizationResponseURL: string): Promise<void> {
const url = new URL(authorizationResponseURL);
const code = url.searchParams.get('code');
if (!code) {
throw new Error("Code not received");
}
const currentState = this.states.get(username);
const currentState = this.states.get(userDid);
let newState = { ...currentState, code };
this.states.set(username, newState);
this.states.set(userDid, newState);

this.tokenRequest(newState).then(tokenResponse => {
newState = { ...newState, tokenResponse }
this.states.set(username, newState);
this.credentialRequests(username, newState).catch(e => {
this.states.set(userDid, newState);
this.credentialRequests(userDid, newState).catch(e => {
console.error("Credential requests failed with error : ", e)
});
})
Expand Down Expand Up @@ -267,7 +265,7 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei
data.append('code', state.code);
data.append('redirect_uri', config.walletClientUrl);
data.append('code_verifier', state.code_verifier);
const user = (await getUserByUsername(state.username)).unwrap();
const user = (await getUserByDID(state.userDid)).unwrap();
data.append('client_id', user.did);
break;
case GrantType.PRE_AUTHORIZED_CODE:
Expand Down Expand Up @@ -314,7 +312,7 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei
/**
* @throws
*/
private async credentialRequests(username: string, state: IssuanceState) {
private async credentialRequests(userDid: string, state: IssuanceState) {

console.log("State = ", state)
const httpHeader = {
Expand All @@ -323,7 +321,7 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei

const c_nonce = state.tokenResponse.c_nonce;

const { proof_jwt } = await this.walletKeyStore.generateOpenid4vciProof(username, state.credentialIssuerMetadata.credential_issuer, c_nonce);
const { proof_jwt } = await this.walletKeyStore.generateOpenid4vciProof(userDid, state.credentialIssuerMetadata.credential_issuer, c_nonce);

const credentialEndpoint = state.credentialIssuerMetadata.credential_endpoint;

Expand Down Expand Up @@ -356,7 +354,7 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei

for (const response of credentialResponses) {
console.log("Response = ", response)
this.handleCredentialStorage(username, response);
this.handleCredentialStorage(userDid, response);
}
console.log("=====FINISHED OID4VCI")
return;
Expand All @@ -372,7 +370,7 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei
{},
{ headers: defferedCredentialReqHeader } )
.then((res) => {
this.handleCredentialStorage(state.username, res.data);
this.handleCredentialStorage(state.userDid, res.data);
})
.catch(err => {
setTimeout(() => {
Expand All @@ -383,14 +381,14 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei

}

private async handleCredentialStorage(username: string, credentialResponse: CredentialResponseSchemaType) {
const userRes = await getUserByUsername(username);
private async handleCredentialStorage(userDid: string, credentialResponse: CredentialResponseSchemaType) {
const userRes = await getUserByDID(userDid);
if (userRes.err) {
return;
}
const user = userRes.unwrap();

const { legalPerson } = this.states.get(username);
const { legalPerson } = this.states.get(userDid);
console.log("Legal person = ", legalPerson)
const credentialPayload = JSON.parse(base64url.decode(credentialResponse.credential.split('.')[1]))
const type = credentialPayload.vc.type as string[];
Expand Down Expand Up @@ -450,4 +448,4 @@ export class OpenidForCredentialIssuanceService implements OpenidCredentialRecei
private static generatePresentableFormat(credentialSubjectMetadata: any, verifiableCredential: any): any {
return getLeafNodesWithPath(verifiableCredential, credentialSubjectMetadata)
}
}
}
Loading

0 comments on commit 7e0353d

Please sign in to comment.