diff --git a/packages/domain-core/src/Domain/Common/Uuid.ts b/packages/domain-core/src/Domain/Common/Uuid.ts index bcba6f37f..8e567de59 100644 --- a/packages/domain-core/src/Domain/Common/Uuid.ts +++ b/packages/domain-core/src/Domain/Common/Uuid.ts @@ -1,6 +1,7 @@ import { ValueObject } from '../Core/ValueObject' import { Result } from '../Core/Result' import { UuidProps } from './UuidProps' +import { Validator } from '../Core/Validator' export class Uuid extends ValueObject { get value(): string { @@ -12,8 +13,9 @@ export class Uuid extends ValueObject { } static create(uuid: string): Result { - if (!!uuid === false || uuid.length === 0) { - return Result.fail('Uuid cannot be empty') + const validUuidOrError = Validator.isValidUuid(uuid) + if (validUuidOrError.isFailed()) { + return Result.fail(validUuidOrError.getError()) } else { return Result.ok(new Uuid({ value: uuid })) } diff --git a/packages/domain-core/src/Domain/Core/Validator.spec.ts b/packages/domain-core/src/Domain/Core/Validator.spec.ts new file mode 100644 index 000000000..eac99995a --- /dev/null +++ b/packages/domain-core/src/Domain/Core/Validator.spec.ts @@ -0,0 +1,32 @@ +import { Validator } from './Validator' + +describe('Validator', () => { + const validUuids = [ + '2221101c-1da9-4d2b-9b32-b8be2a8d1c82', + 'c08f2f29-a74b-42b4-aefd-98af9832391c', + 'b453fa64-1493-443b-b5bb-bca7b9c696c7', + ] + + const invalidUuids = [ + 123, + 'someone@127.0.0.1', + '', + null, + 'b453fa64-1493-443b-b5bb-ca7b9c696c7', + 'c08f*f29-a74b-42b4-aefd-98af9832391c', + 'c08f*f29-a74b-42b4-aefd-98af9832391c', + '../../escaped.sh', + ] + + it('should validate proper uuids', () => { + for (const validUuid of validUuids) { + expect(Validator.isValidUuid(validUuid)).toBeTruthy() + } + }) + + it('should not validate invalid uuids', () => { + for (const invalidUuid of invalidUuids) { + expect(Validator.isValidUuid(invalidUuid as string)).toBeFalsy() + } + }) +}) diff --git a/packages/domain-core/src/Domain/Core/Validator.ts b/packages/domain-core/src/Domain/Core/Validator.ts new file mode 100644 index 000000000..9594c5ffe --- /dev/null +++ b/packages/domain-core/src/Domain/Core/Validator.ts @@ -0,0 +1,14 @@ +import { Result } from './Result' + +export class Validator { + private static readonly UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i + + static isValidUuid(value: string): Result { + const matchesUuidRegex = String(value).toLowerCase().match(Validator.UUID_REGEX) !== null + if (matchesUuidRegex) { + return Result.ok() + } + + return Result.fail(`Given value is not a valid uuid: ${value}`) + } +} diff --git a/packages/domain-core/src/Domain/Revision/ContentType.ts b/packages/domain-core/src/Domain/Revision/ContentType.ts new file mode 100644 index 000000000..232dd0bf8 --- /dev/null +++ b/packages/domain-core/src/Domain/Revision/ContentType.ts @@ -0,0 +1,22 @@ +import { ValueObject } from '../Core/ValueObject' +import { Result } from '../Core/Result' +import { ContentTypeProps } from './ContentTypeProps' +import { ContentType as ContentTypeValues } from '@standardnotes/common' + +export class ContentType extends ValueObject { + get value(): string | null { + return this.props.value + } + + private constructor(props: ContentTypeProps) { + super(props) + } + + static create(contentType: string | null): Result { + if (contentType !== null && !Object.values(ContentTypeValues).includes(contentType as ContentTypeValues)) { + return Result.fail(`Value is not a valid content type: ${contentType}`) + } else { + return Result.ok(new ContentType({ value: contentType })) + } + } +} diff --git a/packages/domain-core/src/Domain/Revision/ContentTypeProps.ts b/packages/domain-core/src/Domain/Revision/ContentTypeProps.ts new file mode 100644 index 000000000..e8ad02bb9 --- /dev/null +++ b/packages/domain-core/src/Domain/Revision/ContentTypeProps.ts @@ -0,0 +1,3 @@ +export interface ContentTypeProps { + value: string | null +} diff --git a/packages/domain-core/src/Domain/Revision/Revision.ts b/packages/domain-core/src/Domain/Revision/Revision.ts new file mode 100644 index 000000000..1402aea12 --- /dev/null +++ b/packages/domain-core/src/Domain/Revision/Revision.ts @@ -0,0 +1,19 @@ +import { Entity } from '../Core/Entity' +import { Result } from '../Core/Result' +import { UniqueEntityId } from '../Core/UniqueEntityId' + +import { RevisionProps } from './RevisionProps' + +export class Revision extends Entity { + get id(): UniqueEntityId { + return this._id + } + + private constructor(props: RevisionProps, id?: UniqueEntityId) { + super(props, id) + } + + static create(props: RevisionProps, id?: UniqueEntityId): Result { + return Result.ok(new Revision(props, id)) + } +} diff --git a/packages/domain-core/src/Domain/Revision/RevisionProps.ts b/packages/domain-core/src/Domain/Revision/RevisionProps.ts new file mode 100644 index 000000000..17572419f --- /dev/null +++ b/packages/domain-core/src/Domain/Revision/RevisionProps.ts @@ -0,0 +1,14 @@ +import { Uuid } from '../Common/Uuid' +import { ContentType } from './ContentType' + +export interface RevisionProps { + itemUuid: Uuid + content: string | null + contentType: ContentType + itemsKeyId: string | null + encItemKey: string | null + authHash: string | null + creationDate: Date + createdAt: Date + updatedAt: Date +} diff --git a/packages/domain-core/src/Domain/index.ts b/packages/domain-core/src/Domain/index.ts index 4d3137b30..5dbf6b75f 100644 --- a/packages/domain-core/src/Domain/index.ts +++ b/packages/domain-core/src/Domain/index.ts @@ -8,7 +8,13 @@ export * from './Core/Entity' export * from './Core/Id' export * from './Core/Result' export * from './Core/UniqueEntityId' +export * from './Core/Validator' export * from './Core/ValueObject' export * from './Core/ValueObjectProps' export * from './Map/MapInterface' + +export * from './Revision/ContentType' +export * from './Revision/ContentTypeProps' +export * from './Revision/Revision' +export * from './Revision/RevisionProps'