Skip to content

Commit

Permalink
modifies id generation logic for status credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
kezike committed Apr 23, 2024
1 parent 1d8d917 commit 07056ab
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 20 deletions.
35 changes: 22 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ const credential = {
};
const credentialWithStatus = await statusManager.allocateStatus({
credential,
statusPurposes: ['revocation']
statusPurposes: ['revocation', 'suspension']
});
console.log(credentialWithStatus);
/*
Expand All @@ -127,18 +127,27 @@ console.log(credentialWithStatus);
issuer: 'did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC',
validFrom: '2020-03-10T04:24:12.164Z',
credentialSubject: { id: 'did:example:abcdef' },
credentialStatus: {
id: 'https://university-xyz.github.io/credential-status/V27UAUYPNR#1',
type: 'BitstringStatusListEntry',
statusPurpose: 'revocation',
statusListIndex: '1',
statusListCredential: 'https://university-xyz.github.io/credential-status/V27UAUYPNR'
}
credentialStatus: [
{
id: 'https://credentials.example.edu/status/Uz42qSDSXTcoLH7kZ6ST#1',
type: 'BitstringStatusListEntry',
statusPurpose: 'revocation',
statusListIndex: '1',
statusListCredential: 'https://credentials.example.edu/status/Uz42qSDSXTcoLH7kZ6ST'
},
{
id: 'https://credentials.example.edu/status/9kGimd8POqM88l32F9aT#1',
type: 'BitstringStatusListEntry',
statusPurpose: 'suspension',
statusListIndex: '1',
statusListCredential: 'https://credentials.example.edu/status/9kGimd8POqM88l32F9aT'
}
]
}
*/
```

**Note:** You can also call `allocateRevocationStatus(credential)` to achieve the same effect as `allocateStatus({ credential, statusPurposes: ['revocation'] })` and `allocateSuspensionStatus(credential)` to achieve the same effect as `allocateStatus({ credential, statusPurposes: ['suspension'] })`.
**Note:** You can also call `allocateRevocationStatus(credential)` to achieve the same effect as `allocateStatus({ credential, statusPurposes: ['revocation'] })`, `allocateSuspensionStatus(credential)` to achieve the same effect as `allocateStatus({ credential, statusPurposes: ['suspension'] })`, and `allocateSupportedStatuses(credential)` to achieve the same effect as `allocateStatus({ credential, statusPurposes: ['revocation', 'suspension'] })`.

Additionally, if the caller invokes `allocateStatus` multiple times with the same credential ID against the same instance of a credential status manager, the library will not allocate a new entry. It will just return a credential with the same status info as it did in the previous invocation.

Expand All @@ -160,10 +169,10 @@ console.log(statusCredential);
'@context': [
'https://www.w3.org/ns/credentials/v2'
],
id: 'https://university-xyz.github.io/credential-status/V27UAUYPNR',
id: 'https://university-xyz.github.io/credential-status/Uz42qSDSXTcoLH7kZ6ST',
type: [ 'VerifiableCredential', 'BitstringStatusListCredential' ],
credentialSubject: {
id: 'https://university-xyz.github.io/credential-status/V27UAUYPNR#list',
id: 'https://university-xyz.github.io/credential-status/Uz42qSDSXTcoLH7kZ6ST#list',
type: 'BitstringStatusList',
encodedList: 'H4sIAAAAAAAAA-3BMQ0AAAACIGf_0LbwAhoAAAAAAAAAAAAAAIC_AfqBUGnUMAAA',
statusPurpose: 'revocation'
Expand All @@ -188,12 +197,12 @@ console.log(credentialStatus);
/*
{
revocation: {
statusCredentialId: 'V27UAUYPNR',
statusCredentialId: 'Uz42qSDSXTcoLH7kZ6ST',
statusListIndex: 1,
valid: true
},
suspension: {
statusCredentialId: '4R7EA3YPTR',
statusCredentialId: '9kGimd8POqM88l32F9aT',
statusListIndex: 1,
valid: false
}
Expand Down
19 changes: 15 additions & 4 deletions src/credential-status-manager-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from './errors.js';
import {
DidMethod,
MAX_ID_LENGTH,
MAX_CREDENTIAL_ID_LENGTH,
getCredentialSubjectObject,
getDateString,
getSigningMaterial,
Expand All @@ -25,6 +25,12 @@ import {
// Number of credentials tracked in a status credential
const STATUS_CREDENTIAL_LIST_SIZE = 100000;

// Length of status credential ID
const STATUS_CREDENTIAL_ID_LENGTH = 20;

// Character set of status credential ID
const STATUS_CREDENTIAL_ID_CHAR_SET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

// Status credential type
const STATUS_CREDENTIAL_TYPE = 'BitstringStatusListCredential';

Expand Down Expand Up @@ -235,7 +241,12 @@ export abstract class BaseCredentialStatusManager {
// Note: We assume this method will never generate an ID that
// has previously been generated for a status credential in this system
generateStatusCredentialId(): string {
return Math.random().toString(36).substring(2, 12).toUpperCase();
let statusCredentialId = '';
const charSetLength = STATUS_CREDENTIAL_ID_CHAR_SET.length;
for (let i = 0; i < STATUS_CREDENTIAL_ID_LENGTH; i++) {
statusCredentialId += STATUS_CREDENTIAL_ID_CHAR_SET.charAt(Math.floor(Math.random() * charSetLength));
}
return statusCredentialId;
}

// generates new user credential ID
Expand Down Expand Up @@ -284,8 +295,8 @@ export abstract class BaseCredentialStatusManager {
} else {
if (!isValidCredentialId(credentialCopy.id)) {
throw new BadRequestError({
message: 'The ID must be a URL, UUID, or DID ' +
`that is no more than ${MAX_ID_LENGTH} characters in length.`
message: 'The credential ID must be a URL, UUID, or DID ' +
`that is no more than ${MAX_CREDENTIAL_ID_LENGTH} characters in length.`
});
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ const didKeyDriver = DidKey.driver();
// Document loader
const documentLoader = securityLoader().build();

// Max length for IDs
export const MAX_ID_LENGTH = 64;
// Max length for credential IDs
export const MAX_CREDENTIAL_ID_LENGTH = 64;

// DID method used to sign credentials
export enum DidMethod {
Expand Down Expand Up @@ -219,7 +219,7 @@ export function deriveStatusCredentialId(statusCredentialUrl: string): string {
// determines if credential ID is valid
export function isValidCredentialId(credentialId: string): boolean {
const isValidFormat = URL.canParse(credentialId) || uuid.validate(credentialId);
const isValidLength = credentialId.length <= MAX_ID_LENGTH;
const isValidLength = credentialId.length <= MAX_CREDENTIAL_ID_LENGTH;
return isValidFormat && isValidLength;
}

Expand Down

0 comments on commit 07056ab

Please sign in to comment.