diff --git a/src/datastore/local-store/repos/api-key.repo.spec.ts b/src/datastore/local-store/repos/api-key.repo.spec.ts index 48c5dcb9..d664a5a7 100644 --- a/src/datastore/local-store/repos/api-key.repo.spec.ts +++ b/src/datastore/local-store/repos/api-key.repo.spec.ts @@ -2,6 +2,7 @@ import { createMock } from '@golevelup/ts-jest'; import { ConfigService } from '@nestjs/config'; import { ApiKeyRepo } from '~/auth/repos/api-key.repo'; +import { AppNotFoundError } from '~/common/errors'; import { LocalApiKeysRepo } from '~/datastore/local-store/repos/api-key.repo'; import { defaultUser } from '~/users/user.consts'; @@ -23,4 +24,16 @@ describe('LocalApiKeyRepo', () => { return expect(repo.getUserByApiKey(config)).resolves.toEqual(defaultUser); }); + + it.each(['constructor', '__proto__', 'toString', 'valueOf', 'hasOwnProperty'])( + 'should not treat the Object.prototype property "%s" as a configured key', + key => { + const mockConfig = createMock(); + mockConfig.getOrThrow.mockReturnValue(config); + + const repo = new LocalApiKeysRepo(mockConfig); + + return expect(repo.getUserByApiKey(key)).rejects.toThrow(AppNotFoundError); + } + ); }); diff --git a/src/datastore/local-store/repos/api-key.repo.ts b/src/datastore/local-store/repos/api-key.repo.ts index 5f26cfcf..2df33069 100644 --- a/src/datastore/local-store/repos/api-key.repo.ts +++ b/src/datastore/local-store/repos/api-key.repo.ts @@ -11,7 +11,7 @@ import { defaultUser } from '~/users/user.consts'; @Injectable() export class LocalApiKeysRepo implements ApiKeyRepo { - private apiKeys: Record = {}; + private apiKeys: Record = Object.create(null); constructor(readonly config: ConfigService) { const givenApiKeys = config.getOrThrow('API_KEYS'); diff --git a/src/signing/services/local-signing.service.spec.ts b/src/signing/services/local-signing.service.spec.ts index 6b1873b3..02b5be97 100644 --- a/src/signing/services/local-signing.service.spec.ts +++ b/src/signing/services/local-signing.service.spec.ts @@ -75,6 +75,13 @@ describe('LocalSigningService', () => { it('should throw if an Account is not loaded', () => { expect(() => service.getAddressByHandle('badId')).toThrow(AppNotFoundError); }); + + it.each(['constructor', '__proto__', 'toString'])( + 'should throw for the Object.prototype property "%s" when it is not loaded', + handle => { + expect(() => service.getAddressByHandle(handle)).toThrow(AppNotFoundError); + } + ); }); describe('isAddress', () => { @@ -122,5 +129,13 @@ describe('LocalSigningService', () => { await expect(service.addSigner(handle, mnemonic)).rejects.toThrow(AppConflictError); }); + + it('should add a signer whose handle is an Object.prototype property name', async () => { + const handle = 'constructor'; + const expectedAddress = '15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5'; + + await expect(service.addSigner(handle, '//Alice')).resolves.toBe(expectedAddress); + await expect(service.getAddressByHandle(handle)).resolves.toBe(expectedAddress); + }); }); }); diff --git a/src/signing/services/local-signing.service.ts b/src/signing/services/local-signing.service.ts index 3ee3c403..cf667089 100644 --- a/src/signing/services/local-signing.service.ts +++ b/src/signing/services/local-signing.service.ts @@ -7,7 +7,7 @@ import { PolymeshService } from '~/polymesh/polymesh.service'; import { SigningService } from '~/signing/services/signing.service'; export class LocalSigningService extends SigningService { - private addressBook: Record = {}; + private addressBook: Record = Object.create(null); constructor( protected readonly signingManager: LocalSigningManager,