Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: remove named capture groups #1378

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {

describe('identifiers', () => {
describe('indySdkAnonCredsRegistryIdentifierRegex', () => {
test('matches against a legacy indy did, schema id, credential definition id and revocation registry id', () => {
test('matches against a legacy schema id, credential definition id and revocation registry id', () => {
const did = '7Tqg6BwSSWapxgUDm9KKgg'
const schemaId = 'BQ42WeE24jFHeyGg8x9XAz:2:Medical Bill:1.0'
const credentialDefinitionId = 'N7baRMcyvPwWc8v85CtZ6e:3:CL:100669:SCH Employee ID'
Expand Down
128 changes: 92 additions & 36 deletions packages/indy-sdk/src/anoncreds/utils/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,28 @@
import { DID_INDY_REGEX } from '../../utils/did'

const didIndyAnonCredsBase =
/(?<did>did:indy:(?<namespace>((?:[a-z][_a-z0-9-]*)(?::[a-z][_a-z0-9-]*)?)):(?<namespaceIdentifier>([1-9A-HJ-NP-Za-km-z]{21,22})))\/anoncreds\/v0/
/(did:indy:((?:[a-z][_a-z0-9-]*)(?::[a-z][_a-z0-9-]*)?):([1-9A-HJ-NP-Za-km-z]{21,22}))\/anoncreds\/v0/

// did:indy:<namespace>:<namespaceIdentifier>/anoncreds/v0/SCHEMA/<schemaName>/<schemaVersion>
const didIndySchemaIdRegex = new RegExp(
`^${didIndyAnonCredsBase.source}/SCHEMA/(?<schemaName>.+)/(?<schemaVersion>[0-9.]+)$`
)
const didIndySchemaIdRegex = new RegExp(`^${didIndyAnonCredsBase.source}/SCHEMA/(.+)/([0-9.]+)$`)

// <namespaceIdentifier>:2:<schemaName>:<schemaVersion>
const legacyIndySchemaIdRegex =
/^(?<did>(?<namespaceIdentifier>[a-zA-Z0-9]{21,22})):2:(?<schemaName>.+):(?<schemaVersion>[0-9.]+)$/
const legacyIndySchemaIdRegex = /^([a-zA-Z0-9]{21,22}):2:(.+):([0-9.]+)$/

// did:indy:<namespace>:<namespaceIdentifier>/anoncreds/v0/CLAIM_DEF/<schemaSeqNo>/<tag>
const didIndyCredentialDefinitionIdRegex = new RegExp(
`^${didIndyAnonCredsBase.source}/CLAIM_DEF/(?<schemaSeqNo>[1-9][0-9]*)/(?<tag>.+)$`
)
const didIndyCredentialDefinitionIdRegex = new RegExp(`^${didIndyAnonCredsBase.source}/CLAIM_DEF/([1-9][0-9]*)/(.+)$`)

// <namespaceIdentifier>:3:CL:<schemaSeqNo>:<tag>
const legacyIndyCredentialDefinitionIdRegex =
/^(?<did>(?<namespaceIdentifier>[a-zA-Z0-9]{21,22})):3:CL:(?<schemaSeqNo>[1-9][0-9]*):(?<tag>.+)$/
const legacyIndyCredentialDefinitionIdRegex = /^([a-zA-Z0-9]{21,22}):3:CL:([1-9][0-9]*):(.+)$/

// did:indy:<namespace>:<namespaceIdentifier>/anoncreds/v0/REV_REG_DEF/<schemaSeqNo>/<credentialDefinitionTag>/<revocationRegistryTag>
const didIndyRevocationRegistryIdRegex = new RegExp(
`^${didIndyAnonCredsBase.source}/REV_REG_DEF/(?<schemaSeqNo>[1-9][0-9]*)/(?<credentialDefinitionTag>.+)/(?<revocationRegistryTag>.+)$`
`^${didIndyAnonCredsBase.source}/REV_REG_DEF/([1-9][0-9]*)/(.+)/(.+)$`
)

// <namespaceIdentifier>:4:<schemaSeqNo>:3:CL:<credentialDefinitionTag>:CL_ACCUM:<revocationRegistryTag>
const legacyIndyRevocationRegistryIdRegex =
/^(?<did>(?<namespaceIdentifier>[a-zA-Z0-9]{21,22})):4:[a-zA-Z0-9]{21,22}:3:CL:(?<schemaSeqNo>[1-9][0-9]*):(?<credentialDefinitionTag>.+):CL_ACCUM:(?<revocationRegistryTag>.+)$/
/^([a-zA-Z0-9]{21,22}):4:[a-zA-Z0-9]{21,22}:3:CL:([1-9][0-9]*):(.+):CL_ACCUM:(.+)$/

// combines both legacy and did:indy anoncreds identifiers and also the issuer id
const indySdkAnonCredsRegexes = [
Expand All @@ -58,7 +52,7 @@ const indySdkAnonCredsRegexes = [
]

export const indySdkAnonCredsRegistryIdentifierRegex = new RegExp(
indySdkAnonCredsRegexes.map((r) => r.source.replace(/(\?<[a-zA-Z]+>)?/g, '')).join('|')
indySdkAnonCredsRegexes.map((r) => r.source).join('|')
)

export function getDidIndySchemaId(namespace: string, unqualifiedDid: string, name: string, version: string) {
Expand Down Expand Up @@ -110,12 +104,33 @@ interface ParsedSchemaId {
namespace?: string
}

export function parseSchemaId(schemaId: string) {
const match = schemaId.match(didIndySchemaIdRegex) ?? schemaId.match(legacyIndySchemaIdRegex)

if (!match) throw new Error(`Invalid schema id: ${schemaId}`)

return match.groups as unknown as ParsedSchemaId
export function parseSchemaId(schemaId: string): ParsedSchemaId {
const didIndyMatch = schemaId.match(didIndySchemaIdRegex)
if (didIndyMatch) {
const [, did, namespace, namespaceIdentifier, schemaName, schemaVersion] = didIndyMatch

return {
did,
namespaceIdentifier,
schemaName,
schemaVersion,
namespace,
}
}

const legacyMatch = schemaId.match(legacyIndySchemaIdRegex)
if (legacyMatch) {
const [, did, schemaName, schemaVersion] = legacyMatch

return {
did,
namespaceIdentifier: did,
schemaName,
schemaVersion,
}
}

throw new Error(`Invalid schema id: ${schemaId}`)
}

interface ParsedCredentialDefinitionId {
Expand All @@ -126,14 +141,33 @@ interface ParsedCredentialDefinitionId {
namespace?: string
}

export function parseCredentialDefinitionId(credentialDefinitionId: string) {
const match =
credentialDefinitionId.match(didIndyCredentialDefinitionIdRegex) ??
credentialDefinitionId.match(legacyIndyCredentialDefinitionIdRegex)

if (!match) throw new Error(`Invalid credential definition id: ${credentialDefinitionId}`)

return match.groups as unknown as ParsedCredentialDefinitionId
export function parseCredentialDefinitionId(credentialDefinitionId: string): ParsedCredentialDefinitionId {
const didIndyMatch = credentialDefinitionId.match(didIndyCredentialDefinitionIdRegex)
if (didIndyMatch) {
const [, did, namespace, namespaceIdentifier, schemaSeqNo, tag] = didIndyMatch

return {
did,
namespaceIdentifier,
schemaSeqNo,
tag,
namespace,
}
}

const legacyMatch = credentialDefinitionId.match(legacyIndyCredentialDefinitionIdRegex)
if (legacyMatch) {
const [, did, schemaSeqNo, tag] = legacyMatch

return {
did,
namespaceIdentifier: did,
schemaSeqNo,
tag,
}
}

throw new Error(`Invalid credential definition id: ${credentialDefinitionId}`)
}

interface ParsedRevocationRegistryId {
Expand All @@ -145,12 +179,34 @@ interface ParsedRevocationRegistryId {
namespace?: string
}

export function parseRevocationRegistryId(revocationRegistryId: string) {
const match =
revocationRegistryId.match(didIndyRevocationRegistryIdRegex) ??
revocationRegistryId.match(legacyIndyRevocationRegistryIdRegex)

if (!match) throw new Error(`Invalid revocation registry id: ${revocationRegistryId}`)

return match.groups as unknown as ParsedRevocationRegistryId
export function parseRevocationRegistryId(revocationRegistryId: string): ParsedRevocationRegistryId {
const didIndyMatch = revocationRegistryId.match(didIndyRevocationRegistryIdRegex)
if (didIndyMatch) {
const [, did, namespace, namespaceIdentifier, schemaSeqNo, credentialDefinitionTag, revocationRegistryTag] =
didIndyMatch

return {
did,
namespaceIdentifier,
schemaSeqNo,
credentialDefinitionTag,
revocationRegistryTag,
namespace,
}
}

const legacyMatch = revocationRegistryId.match(legacyIndyRevocationRegistryIdRegex)

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data

This [regular expression](1) that depends on [library input](2) may run slow on strings with many repetitions of 'a:CL_ACCUM:a'. This [regular expression](1) that depends on [library input](3) may run slow on strings with many repetitions of 'a:CL_ACCUM:a'.
if (legacyMatch) {
const [, did, schemaSeqNo, credentialDefinitionTag, revocationRegistryTag] = legacyMatch

return {
did,
namespaceIdentifier: did,
schemaSeqNo,
credentialDefinitionTag,
revocationRegistryTag,
}
}

throw new Error(`Invalid revocation registry id: ${revocationRegistryId}`)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {

describe('identifiers', () => {
describe('indyVdrAnonCredsRegistryIdentifierRegex', () => {
test('matches against a legacy indy did, schema id, credential definition id and revocation registry id', () => {
test('matches against a legacy schema id, credential definition id and revocation registry id', () => {
const did = '7Tqg6BwSSWapxgUDm9KKgg'
const schemaId = 'BQ42WeE24jFHeyGg8x9XAz:2:Medical Bill:1.0'
const credentialDefinitionId = 'N7baRMcyvPwWc8v85CtZ6e:3:CL:100669:SCH Employee ID'
Expand Down
128 changes: 92 additions & 36 deletions packages/indy-vdr/src/anoncreds/utils/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,28 @@
import { DID_INDY_REGEX } from '../../utils/did'

const didIndyAnonCredsBase =
/(?<did>did:indy:(?<namespace>((?:[a-z][_a-z0-9-]*)(?::[a-z][_a-z0-9-]*)?)):(?<namespaceIdentifier>([1-9A-HJ-NP-Za-km-z]{21,22})))\/anoncreds\/v0/
/(did:indy:((?:[a-z][_a-z0-9-]*)(?::[a-z][_a-z0-9-]*)?):([1-9A-HJ-NP-Za-km-z]{21,22}))\/anoncreds\/v0/

// did:indy:<namespace>:<namespaceIdentifier>/anoncreds/v0/SCHEMA/<schemaName>/<schemaVersion>
const didIndySchemaIdRegex = new RegExp(
`^${didIndyAnonCredsBase.source}/SCHEMA/(?<schemaName>.+)/(?<schemaVersion>[0-9.]+)$`
)
const didIndySchemaIdRegex = new RegExp(`^${didIndyAnonCredsBase.source}/SCHEMA/(.+)/([0-9.]+)$`)

// <namespaceIdentifier>:2:<schemaName>:<schemaVersion>
const legacyIndySchemaIdRegex =
/^(?<did>(?<namespaceIdentifier>[a-zA-Z0-9]{21,22})):2:(?<schemaName>.+):(?<schemaVersion>[0-9.]+)$/
const legacyIndySchemaIdRegex = /^([a-zA-Z0-9]{21,22}):2:(.+):([0-9.]+)$/

// did:indy:<namespace>:<namespaceIdentifier>/anoncreds/v0/CLAIM_DEF/<schemaSeqNo>/<tag>
const didIndyCredentialDefinitionIdRegex = new RegExp(
`^${didIndyAnonCredsBase.source}/CLAIM_DEF/(?<schemaSeqNo>[1-9][0-9]*)/(?<tag>.+)$`
)
const didIndyCredentialDefinitionIdRegex = new RegExp(`^${didIndyAnonCredsBase.source}/CLAIM_DEF/([1-9][0-9]*)/(.+)$`)

// <namespaceIdentifier>:3:CL:<schemaSeqNo>:<tag>
const legacyIndyCredentialDefinitionIdRegex =
/^(?<did>(?<namespaceIdentifier>[a-zA-Z0-9]{21,22})):3:CL:(?<schemaSeqNo>[1-9][0-9]*):(?<tag>.+)$/
const legacyIndyCredentialDefinitionIdRegex = /^([a-zA-Z0-9]{21,22}):3:CL:([1-9][0-9]*):(.+)$/

// did:indy:<namespace>:<namespaceIdentifier>/anoncreds/v0/REV_REG_DEF/<schemaSeqNo>/<credentialDefinitionTag>/<revocationRegistryTag>
const didIndyRevocationRegistryIdRegex = new RegExp(
`^${didIndyAnonCredsBase.source}/REV_REG_DEF/(?<schemaSeqNo>[1-9][0-9]*)/(?<credentialDefinitionTag>.+)/(?<revocationRegistryTag>.+)$`
`^${didIndyAnonCredsBase.source}/REV_REG_DEF/([1-9][0-9]*)/(.+)/(.+)$`
)

// <namespaceIdentifier>:4:<schemaSeqNo>:3:CL:<credentialDefinitionTag>:CL_ACCUM:<revocationRegistryTag>
const legacyIndyRevocationRegistryIdRegex =
/^(?<did>(?<namespaceIdentifier>[a-zA-Z0-9]{21,22})):4:[a-zA-Z0-9]{21,22}:3:CL:(?<schemaSeqNo>[1-9][0-9]*):(?<credentialDefinitionTag>.+):CL_ACCUM:(?<revocationRegistryTag>.+)$/
/^([a-zA-Z0-9]{21,22}):4:[a-zA-Z0-9]{21,22}:3:CL:([1-9][0-9]*):(.+):CL_ACCUM:(.+)$/

// combines both legacy and did:indy anoncreds identifiers and also the issuer id
const indyVdrAnonCredsRegexes = [
Expand All @@ -58,7 +52,7 @@ const indyVdrAnonCredsRegexes = [
]

export const indyVdrAnonCredsRegistryIdentifierRegex = new RegExp(
indyVdrAnonCredsRegexes.map((r) => r.source.replace(/(\?<[a-zA-Z]+>)?/g, '')).join('|')
indyVdrAnonCredsRegexes.map((r) => r.source).join('|')
)

export function getDidIndySchemaId(namespace: string, unqualifiedDid: string, name: string, version: string) {
Expand Down Expand Up @@ -110,12 +104,33 @@ interface ParsedSchemaId {
namespace?: string
}

export function parseSchemaId(schemaId: string) {
const match = schemaId.match(didIndySchemaIdRegex) ?? schemaId.match(legacyIndySchemaIdRegex)

if (!match) throw new Error(`Invalid schema id: ${schemaId}`)

return match.groups as unknown as ParsedSchemaId
export function parseSchemaId(schemaId: string): ParsedSchemaId {
const didIndyMatch = schemaId.match(didIndySchemaIdRegex)
if (didIndyMatch) {
const [, did, namespace, namespaceIdentifier, schemaName, schemaVersion] = didIndyMatch

return {
did,
namespaceIdentifier,
schemaName,
schemaVersion,
namespace,
}
}

const legacyMatch = schemaId.match(legacyIndySchemaIdRegex)
if (legacyMatch) {
const [, did, schemaName, schemaVersion] = legacyMatch

return {
did,
namespaceIdentifier: did,
schemaName,
schemaVersion,
}
}

throw new Error(`Invalid schema id: ${schemaId}`)
}

interface ParsedCredentialDefinitionId {
Expand All @@ -126,14 +141,33 @@ interface ParsedCredentialDefinitionId {
namespace?: string
}

export function parseCredentialDefinitionId(credentialDefinitionId: string) {
const match =
credentialDefinitionId.match(didIndyCredentialDefinitionIdRegex) ??
credentialDefinitionId.match(legacyIndyCredentialDefinitionIdRegex)

if (!match) throw new Error(`Invalid credential definition id: ${credentialDefinitionId}`)

return match.groups as unknown as ParsedCredentialDefinitionId
export function parseCredentialDefinitionId(credentialDefinitionId: string): ParsedCredentialDefinitionId {
const didIndyMatch = credentialDefinitionId.match(didIndyCredentialDefinitionIdRegex)
if (didIndyMatch) {
const [, did, namespace, namespaceIdentifier, schemaSeqNo, tag] = didIndyMatch

return {
did,
namespaceIdentifier,
schemaSeqNo,
tag,
namespace,
}
}

const legacyMatch = credentialDefinitionId.match(legacyIndyCredentialDefinitionIdRegex)
if (legacyMatch) {
const [, did, schemaSeqNo, tag] = legacyMatch

return {
did,
namespaceIdentifier: did,
schemaSeqNo,
tag,
}
}

throw new Error(`Invalid credential definition id: ${credentialDefinitionId}`)
}

interface ParsedRevocationRegistryId {
Expand All @@ -145,12 +179,34 @@ interface ParsedRevocationRegistryId {
namespace?: string
}

export function parseRevocationRegistryId(revocationRegistryId: string) {
const match =
revocationRegistryId.match(didIndyRevocationRegistryIdRegex) ??
revocationRegistryId.match(legacyIndyRevocationRegistryIdRegex)

if (!match) throw new Error(`Invalid revocation registry id: ${revocationRegistryId}`)

return match.groups as unknown as ParsedRevocationRegistryId
export function parseRevocationRegistryId(revocationRegistryId: string): ParsedRevocationRegistryId {
const didIndyMatch = revocationRegistryId.match(didIndyRevocationRegistryIdRegex)
if (didIndyMatch) {
const [, did, namespace, namespaceIdentifier, schemaSeqNo, credentialDefinitionTag, revocationRegistryTag] =
didIndyMatch

return {
did,
namespaceIdentifier,
schemaSeqNo,
credentialDefinitionTag,
revocationRegistryTag,
namespace,
}
}

const legacyMatch = revocationRegistryId.match(legacyIndyRevocationRegistryIdRegex)

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data

This [regular expression](1) that depends on [library input](2) may run slow on strings with many repetitions of 'a:CL_ACCUM:a'. This [regular expression](1) that depends on [library input](3) may run slow on strings with many repetitions of 'a:CL_ACCUM:a'.
if (legacyMatch) {
const [, did, schemaSeqNo, credentialDefinitionTag, revocationRegistryTag] = legacyMatch

return {
did,
namespaceIdentifier: did,
schemaSeqNo,
credentialDefinitionTag,
revocationRegistryTag,
}
}

throw new Error(`Invalid revocation registry id: ${revocationRegistryId}`)
}