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

Restrict character sets for attribute values #397

Draft
wants to merge 52 commits into
base: release/v7
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
5df34b7
feat: restrict character sets
Magnus-Kuhn Jan 24, 2025
7efde04
Merge remote-tracking branch 'origin/main' into restrict-character-sets
Magnus-Kuhn Jan 24, 2025
c6eb239
feat: restrict value hints
Magnus-Kuhn Jan 24, 2025
3ae49a0
fix: remove wrong \ in regex
Magnus-Kuhn Jan 24, 2025
2b46a96
refactor: only use unicode codes when necessary
Magnus-Kuhn Jan 25, 2025
aa82195
test: add first character set tests
Magnus-Kuhn Jan 25, 2025
aaf956b
test: add more tests
Magnus-Kuhn Jan 27, 2025
5452b33
fix: import in JobTitle
Magnus-Kuhn Jan 27, 2025
5414c8b
fix: check regex in AbstractXML
Magnus-Kuhn Jan 27, 2025
667a232
fix: undo JSON.stringify replacements
Magnus-Kuhn Jan 28, 2025
03fb0f6
test: remove regex comparison
Magnus-Kuhn Jan 28, 2025
b957dff
test: check error property, change test value to \r
Magnus-Kuhn Jan 28, 2025
9113192
refactor: add character set source warning
Magnus-Kuhn Jan 28, 2025
6c690be
test: fix names containing numbers
Magnus-Kuhn Jan 28, 2025
378fe0e
Merge branch 'main' into restrict-character-sets
Magnus-Kuhn Jan 28, 2025
5db6869
test: fix more names containing numbers
Magnus-Kuhn Jan 28, 2025
be05487
refactor: test variable naming
Magnus-Kuhn Jan 28, 2025
2fd930e
test: change test value
Magnus-Kuhn Jan 28, 2025
9cce0af
feat: validate key of rel attribute
Magnus-Kuhn Jan 28, 2025
a3bc119
fix: missing valueHints adaptations
Magnus-Kuhn Jan 28, 2025
5d0b199
refactor: variable naming
Magnus-Kuhn Jan 28, 2025
e833423
fix: move some checks to custom validators
Magnus-Kuhn Jan 28, 2025
a643b22
refactor: remove conditional from test
Magnus-Kuhn Jan 28, 2025
d1fd080
refactor: test variable naming
Magnus-Kuhn Jan 28, 2025
9da1f64
Merge branch 'main' into restrict-character-sets
Magnus-Kuhn Jan 28, 2025
9b06742
Merge branch 'main' into restrict-character-sets
Magnus-Kuhn Jan 29, 2025
4bc90d6
test: more variety in tested characters
Magnus-Kuhn Jan 29, 2025
b052ea0
fix: make ValueHintsOverride work, add tests
Magnus-Kuhn Jan 29, 2025
1fcb037
refactor: clearer datatype explanation
Magnus-Kuhn Jan 29, 2025
63b0269
Merge branch 'main' into restrict-character-sets
Magnus-Kuhn Jan 29, 2025
9d0fdc1
feat: restrict some addresses
Magnus-Kuhn Jan 29, 2025
5fb432e
feat: restrict attributeQueries
Magnus-Kuhn Jan 29, 2025
0806108
Merge branch 'main' into restrict-character-sets
Magnus-Kuhn Jan 30, 2025
8fbfbac
test: don't test NFC normalization
Magnus-Kuhn Jan 30, 2025
00b6346
refactor: namings in the test
Magnus-Kuhn Jan 30, 2025
e17074f
refactor: cleaner test names
Magnus-Kuhn Jan 30, 2025
3241932
refactor: review comments
Magnus-Kuhn Feb 2, 2025
73e9a6a
refactor: remove unneeded code
Magnus-Kuhn Feb 3, 2025
b33c8f4
refactor: import regex in test
Magnus-Kuhn Feb 3, 2025
460b99f
Merge branch 'main' into restrict-character-sets
Magnus-Kuhn Feb 4, 2025
f46b980
feat: don't validate ProprietaryXML/JSON
Magnus-Kuhn Feb 4, 2025
c341628
Merge branch 'main' into restrict-character-sets
jkoenig134 Feb 17, 2025
0c3a889
Merge branch 'main' into restrict-character-sets
Magnus-Kuhn Feb 24, 2025
22158b6
Merge branch 'main' into restrict-character-sets
Magnus-Kuhn Feb 27, 2025
b24c654
Merge branch 'release/v7' into restrict-character-sets
jkoenig134 Mar 5, 2025
e96086e
Merge branch 'release/v7' into restrict-character-sets
mergify[bot] Mar 5, 2025
1c304a9
Merge branch 'release/v7' into restrict-character-sets
mergify[bot] Mar 6, 2025
8d35c75
Merge branch 'release/v7' into restrict-character-sets
mergify[bot] Mar 6, 2025
d9a610c
Merge branch 'release/v7' into restrict-character-sets
mergify[bot] Mar 6, 2025
a40b043
Merge branch 'release/v7' into restrict-character-sets
mergify[bot] Mar 6, 2025
049490c
Merge branch 'release/v7' into restrict-character-sets
mergify[bot] Mar 6, 2025
78298fe
Merge branch 'release/v7' into restrict-character-sets
mergify[bot] Mar 6, 2025
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
3 changes: 2 additions & 1 deletion packages/content/src/attributes/RelationshipAttribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { serialize, type, validate } from "@js-soft/ts-serval";
import { AbstractAttribute, AbstractAttributeJSON, IAbstractAttribute } from "./AbstractAttribute";
import { AttributeValues } from "./AttributeValueTypes";
import { RelationshipAttributeConfidentiality } from "./RelationshipAttributeConfidentiality";
import { characterSets } from "./constants/CharacterSets";

export interface RelationshipAttributeJSON<TValueJSONInterface extends AttributeValues.Relationship.Json = AttributeValues.Relationship.Json> extends AbstractAttributeJSON {
"@type": "RelationshipAttribute";
Expand All @@ -28,7 +29,7 @@ export class RelationshipAttribute<TValueClass extends AttributeValues.Relations
public value: TValueClass;

@serialize()
@validate({ max: 100 })
@validate({ max: 100, regExp: characterSets.din91379DatatypeC })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this key is only machine read, I don't see a reason why we should limit the charset here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reason for validating everything was that integrators can safely copy attributes into their systems, even if they can't handle all characters

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see someone not being able to "handle" this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for creating the norm and making it mandatory was that there were non-conformant IT systems (some that weren't even using UTF8) - see https://www.it-planungsrat.de/fileadmin/beschluesse/2022/Beschluss2022-51_Umsetzung.pdf. I would not be as confident with this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ehm, nope?! The main reason is that we don't want to have ✌🏼😜😜😜🤣😆🥹😅 as a display name or surname.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, then there has been some misunderstanding

public key: string;

@serialize()
Expand Down
7 changes: 4 additions & 3 deletions packages/content/src/attributes/RelationshipAttributeQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ISerializable, Serializable, serialize, type, validate } from "@js-soft
import { CoreAddress, ICoreAddress } from "@nmshd/core-types";
import { AbstractAttributeQuery, AbstractAttributeQueryJSON, IAbstractAttributeQuery } from "./AbstractAttributeQuery";
import { AttributeValues } from "./AttributeValueTypes";
import { characterSets } from "./constants/CharacterSets";
import { IValueHints, ValueHints, ValueHintsJSON } from "./hints";
import { RelationshipAttributeConfidentiality } from "./RelationshipAttributeConfidentiality";
import { PROPRIETARY_ATTRIBUTE_MAX_DESCRIPTION_LENGTH, PROPRIETARY_ATTRIBUTE_MAX_TITLE_LENGTH } from "./types/proprietary/ProprietaryAttributeValue";
Expand Down Expand Up @@ -30,7 +31,7 @@ export interface IRelationshipAttributeCreationHints extends ISerializable {
@type("RelationshipAttributeCreationHints")
export class RelationshipAttributeCreationHints extends Serializable implements IRelationshipAttributeCreationHints {
@serialize()
@validate({ max: PROPRIETARY_ATTRIBUTE_MAX_TITLE_LENGTH })
@validate({ max: PROPRIETARY_ATTRIBUTE_MAX_TITLE_LENGTH, regExp: characterSets.din91379DatatypeC })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are title and description validated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a query has forbidden characters, then there would be no attribute that fits to the query

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ehm, what? this would require that title and description are validated in the attribute itself..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are currently validated in the Proprietary... types

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but also there I'd heavily argue that this is necessary.

public title: string;

@serialize()
Expand All @@ -40,7 +41,7 @@ export class RelationshipAttributeCreationHints extends Serializable implements
public valueType: AttributeValues.Relationship.TypeName;

@serialize()
@validate({ nullable: true, max: PROPRIETARY_ATTRIBUTE_MAX_DESCRIPTION_LENGTH })
@validate({ nullable: true, max: PROPRIETARY_ATTRIBUTE_MAX_DESCRIPTION_LENGTH, regExp: characterSets.din91379DatatypeC })
public description?: string;

@serialize()
Expand Down Expand Up @@ -81,7 +82,7 @@ export interface IRelationshipAttributeQuery extends IAbstractAttributeQuery {
@type("RelationshipAttributeQuery")
export class RelationshipAttributeQuery extends AbstractAttributeQuery implements IRelationshipAttributeQuery {
@serialize()
@validate({ max: 100 })
@validate({ max: 100, regExp: characterSets.din91379DatatypeC })
public key: string;

@serialize()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { serialize, type, validate } from "@js-soft/ts-serval";
import { CoreAddress, ICoreAddress } from "@nmshd/core-types";
import { AbstractAttributeQuery, AbstractAttributeQueryJSON, IAbstractAttributeQuery } from "./AbstractAttributeQuery";
import { characterSets } from "./constants/CharacterSets";
export interface ThirdPartyRelationshipAttributeQueryJSON extends AbstractAttributeQueryJSON {
"@type": "ThirdPartyRelationshipAttributeQuery";
key: string;
Expand All @@ -23,7 +24,7 @@ export enum ThirdPartyRelationshipAttributeQueryOwner {
@type("ThirdPartyRelationshipAttributeQuery")
export class ThirdPartyRelationshipAttributeQuery extends AbstractAttributeQuery implements IThirdPartyRelationshipAttributeQuery {
@serialize()
@validate({ max: 100 })
@validate({ max: 100, regExp: characterSets.din91379DatatypeC })
public key: string;

@serialize()
Expand Down
13 changes: 13 additions & 0 deletions packages/content/src/attributes/constants/CharacterSets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const characterSets: Record<string, RegExp> = {
// DIN91379 character sets from https://xoev.de/schemata/din/91379/2022-08/din-norm-91379-datatypes.xsd
// See the sources in the browser's dev mode, they're not equal to what's initially displayed
// data type A for names of natural persons
din91379DatatypeA:
/^( |'|[,-.]|[A-Z]|[`-z]|~|¨|´|·|[À-Ö]|[Ø-ö]|[ø-ž]|[Ƈ-ƈ]|Ə|Ɨ|[Ơ-ơ]|[Ư-ư]|Ʒ|[Ǎ-ǜ]|[Ǟ-ǟ]|[Ǣ-ǰ]|[Ǵ-ǵ]|[Ǹ-ǿ]|[Ȓ-ȓ]|[Ș-ț]|[Ȟ-ȟ]|[ȧ-ȳ]|ə|ɨ|ʒ|[ʹ-ʺ]|[ʾ-ʿ]|ˈ|ˌ|[Ḃ-ḃ]|[Ḇ-ḇ]|[Ḋ-ḑ]|ḗ|[Ḝ-ḫ]|[ḯ-ḷ]|[Ḻ-ḻ]|[Ṁ-ṉ]|[Ṓ-ṛ]|[Ṟ-ṣ]|[Ṫ-ṯ]|[Ẁ-ẇ]|[Ẍ-ẗ]|ẞ|[Ạ-ỹ]|’|‡|A̋|C(̀|̄|̆|̈|̕|̣|̦|̨̆)|D̂|F(̀|̄)|G̀|H(̄|̦|̱)|J(́|̌)|K(̀|̂|̄|̇|̕|̛|̦|͟H|͟h)|L(̂|̥|̥̄|̦)|M(̀|̂|̆|̐)|N(̂|̄|̆|̦)|P(̀|̄|̕|̣)|R(̆|̥|̥̄)|S(̀|̄|̛̄|̱)|T(̀|̄|̈|̕|̛)|U̇|Z(̀|̄|̆|̈|̧)|a̋|c(̀|̄|̆|̈|̕|̣|̦|̨̆)|d̂|f(̀|̄)|g̀|h(̄|̦)|j́|k(̀|̂|̄|̇|̕|̛|̦|͟h)|l(̂|̥|̥̄|̦)|m(̀|̂|̆|̐)|n(̂|̄|̆|̦)|p(̀|̄|̕|̣)|r(̆|̥|̥̄)|s(̀|̄|̛̄|̱)|t(̀|̄|̕|̛)|u̇|z(̀|̄|̆|̈|̧)|Ç̆|Û̄|ç̆|û̄|ÿ́|Č(̕|̣)|č(̕|̣)|ē̍|Ī́|ī́|ō̍|Ž(̦|̧)|ž(̦|̧)|Ḳ̄|ḳ̄|Ṣ̄|ṣ̄|Ṭ̄|ṭ̄|Ạ̈|ạ̈|Ọ̈|ọ̈|Ụ(̄|̈)|ụ(̄|̈))*$/,
// data type B for all names
din91379DatatypeB:
/^([ -~]|[¡-£]|¥|[§-¬]|[®-·]|[¹-»]|[¿-ž]|[Ƈ-ƈ]|Ə|Ɨ|[Ơ-ơ]|[Ư-ư]|Ʒ|[Ǎ-ǜ]|[Ǟ-ǟ]|[Ǣ-ǰ]|[Ǵ-ǵ]|[Ǹ-ǿ]|[Ȓ-ȓ]|[Ș-ț]|[Ȟ-ȟ]|[ȧ-ȳ]|ə|ɨ|ʒ|[ʹ-ʺ]|[ʾ-ʿ]|ˈ|ˌ|[Ḃ-ḃ]|[Ḇ-ḇ]|[Ḋ-ḑ]|ḗ|[Ḝ-ḫ]|[ḯ-ḷ]|[Ḻ-ḻ]|[Ṁ-ṉ]|[Ṓ-ṛ]|[Ṟ-ṣ]|[Ṫ-ṯ]|[Ẁ-ẇ]|[Ẍ-ẗ]|ẞ|[Ạ-ỹ]|’|‡|€|A̋|C(̀|̄|̆|̈|̕|̣|̦|̨̆)|D̂|F(̀|̄)|G̀|H(̄|̦|̱)|J(́|̌)|K(̀|̂|̄|̇|̕|̛|̦|͟H|͟h)|L(̂|̥|̥̄|̦)|M(̀|̂|̆|̐)|N(̂|̄|̆|̦)|P(̀|̄|̕|̣)|R(̆|̥|̥̄)|S(̀|̄|̛̄|̱)|T(̀|̄|̈|̕|̛)|U̇|Z(̀|̄|̆|̈|̧)|a̋|c(̀|̄|̆|̈|̕|̣|̦|̨̆)|d̂|f(̀|̄)|g̀|h(̄|̦)|j́|k(̀|̂|̄|̇|̕|̛|̦|͟h)|l(̂|̥|̥̄|̦)|m(̀|̂|̆|̐)|n(̂|̄|̆|̦)|p(̀|̄|̕|̣)|r(̆|̥|̥̄)|s(̀|̄|̛̄|̱)|t(̀|̄|̕|̛)|u̇|z(̀|̄|̆|̈|̧)|Ç̆|Û̄|ç̆|û̄|ÿ́|Č(̕|̣)|č(̕|̣)|ē̍|Ī́|ī́|ō̍|Ž(̦|̧)|ž(̦|̧)|Ḳ̄|ḳ̄|Ṣ̄|ṣ̄|Ṭ̄|ṭ̄|Ạ̈|ạ̈|Ọ̈|ọ̈|Ụ(̄|̈)|ụ(̄|̈))*$/,
// data type C for every mandatory character in the norm
din91379DatatypeC:
/^([\u0009-\u000A]|\u000D|[ -~]|[ -¬]|[®-ž]|[Ƈ-ƈ]|Ə|Ɨ|[Ơ-ơ]|[Ư-ư]|Ʒ|[Ǎ-ǜ]|[Ǟ-ǟ]|[Ǣ-ǰ]|[Ǵ-ǵ]|[Ǹ-ǿ]|[Ȓ-ȓ]|[Ș-ț]|[Ȟ-ȟ]|[ȧ-ȳ]|ə|ɨ|ʒ|[ʹ-ʺ]|[ʾ-ʿ]|ˈ|ˌ|[Ḃ-ḃ]|[Ḇ-ḇ]|[Ḋ-ḑ]|ḗ|[Ḝ-ḫ]|[ḯ-ḷ]|[Ḻ-ḻ]|[Ṁ-ṉ]|[Ṓ-ṛ]|[Ṟ-ṣ]|[Ṫ-ṯ]|[Ẁ-ẇ]|[Ẍ-ẗ]|ẞ|[Ạ-ỹ]|’|‡|€|A̋|C(̀|̄|̆|̈|̕|̣|̦|̨̆)|D̂|F(̀|̄)|G̀|H(̄|̦|̱)|J(́|̌)|K(̀|̂|̄|̇|̕|̛|̦|͟H|͟h)|L(̂|̥|̥̄|̦)|M(̀|̂|̆|̐)|N(̂|̄|̆|̦)|P(̀|̄|̕|̣)|R(̆|̥|̥̄)|S(̀|̄|̛̄|̱)|T(̀|̄|̈|̕|̛)|U̇|Z(̀|̄|̆|̈|̧)|a̋|c(̀|̄|̆|̈|̕|̣|̦|̨̆)|d̂|f(̀|̄)|g̀|h(̄|̦)|j́|k(̀|̂|̄|̇|̕|̛|̦|͟h)|l(̂|̥|̥̄|̦)|m(̀|̂|̆|̐)|n(̂|̄|̆|̦)|p(̀|̄|̕|̣)|r(̆|̥|̥̄)|s(̀|̄|̛̄|̱)|t(̀|̄|̕|̛)|u̇|z(̀|̄|̆|̈|̧)|Ç̆|Û̄|ç̆|û̄|ÿ́|Č(̕|̣)|č(̕|̣)|ē̍|Ī́|ī́|ō̍|Ž(̦|̧)|ž(̦|̧)|Ḳ̄|ḳ̄|Ṣ̄|ṣ̄|Ṭ̄|ṭ̄|Ạ̈|ạ̈|Ọ̈|ọ̈|Ụ(̄|̈)|ụ(̄|̈))*$/
};
17 changes: 13 additions & 4 deletions packages/content/src/attributes/hints/ValueHints.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ISerializable, PrimitiveType, Serializable, serialize, type, validate } from "@js-soft/ts-serval";
import { ContentJSON } from "../../ContentJSON";
import { characterSets } from "../constants/CharacterSets";
import { IValueHintsValue, ValueHintsValue, ValueHintsValueJSON } from "./ValueHintsValue";

export interface ValueHintsJSON extends ContentJSON {
Expand Down Expand Up @@ -48,7 +49,7 @@ function serializePropertyHints(hints: ValueHints | ValueHintsOverride, json: Va
@type("ValueHints")
export class ValueHints extends Serializable implements IValueHints {
@serialize()
@validate({ nullable: true, max: 500 })
@validate({ nullable: true, max: 500, regExp: characterSets.din91379DatatypeC })
public editHelp?: string;

@serialize()
Expand All @@ -67,7 +68,7 @@ export class ValueHints extends Serializable implements IValueHints {
@validate({ nullable: true })
public values?: ValueHintsValue[];

@validate({ nullable: true, allowedTypes: [PrimitiveType.Number, PrimitiveType.String, PrimitiveType.Boolean] })
@validate({ nullable: true, allowedTypes: [PrimitiveType.Number, PrimitiveType.String, PrimitiveType.Boolean], customValidator: validateDefaultValue })
@serialize()
public defaultValue?: number | string | boolean;

Expand Down Expand Up @@ -104,7 +105,7 @@ export class ValueHints extends Serializable implements IValueHints {
@type("ValueHintsOverride")
export class ValueHintsOverride extends Serializable implements IValueHintsOverride {
@serialize()
@validate({ nullable: true, max: 500 })
@validate({ nullable: true, max: 500, regExp: characterSets.din91379DatatypeC })
public editHelp?: string;

@serialize()
Expand All @@ -124,7 +125,7 @@ export class ValueHintsOverride extends Serializable implements IValueHintsOverr
public values?: ValueHintsValue[];

@serialize()
@validate({ nullable: true, allowedTypes: [PrimitiveType.Number, PrimitiveType.String, PrimitiveType.Boolean] })
@validate({ nullable: true, allowedTypes: [PrimitiveType.Number, PrimitiveType.String, PrimitiveType.Boolean], customValidator: validateDefaultValue })
public defaultValue?: boolean | number | string;

@serialize()
Expand All @@ -147,3 +148,11 @@ export class ValueHintsOverride extends Serializable implements IValueHintsOverr
return json;
}
}

function validateDefaultValue(defaultValue: string | number | boolean) {
if (typeof defaultValue === "string" && !characterSets.din91379DatatypeC.test(defaultValue)) {
return "Value does not match regular expression /^([\\u0009-\\u000A]|\\u000D|[ -~]|[ -¬]|[®-ž]|[Ƈ-ƈ]|Ə|Ɨ|[Ơ-ơ]|[Ư-ư]|Ʒ|[Ǎ-ǜ]|[Ǟ-ǟ]|[Ǣ-ǰ]|[Ǵ-ǵ]|[Ǹ-ǿ]|[Ȓ-ȓ]|[Ș-ț]|[Ȟ-ȟ]|[ȧ-ȳ]|ə|ɨ|ʒ|[ʹ-ʺ]|[ʾ-ʿ]|ˈ|ˌ|[Ḃ-ḃ]|[Ḇ-ḇ]|[Ḋ-ḑ]|ḗ|[Ḝ-ḫ]|[ḯ-ḷ]|[Ḻ-ḻ]|[Ṁ-ṉ]|[Ṓ-ṛ]|[Ṟ-ṣ]|[Ṫ-ṯ]|[Ẁ-ẇ]|[Ẍ-ẗ]|ẞ|[Ạ-ỹ]|’|‡|€|A̋|C(̀|̄|̆|̈|̕|̣|̦|̨̆)|D̂|F(̀|̄)|G̀|H(̄|̦|̱)|J(́|̌)|K(̀|̂|̄|̇|̕|̛|̦|͟H|͟h)|L(̂|̥|̥̄|̦)|M(̀|̂|̆|̐)|N(̂|̄|̆|̦)|P(̀|̄|̕|̣)|R(̆|̥|̥̄)|S(̀|̄|̛̄|̱)|T(̀|̄|̈|̕|̛)|U̇|Z(̀|̄|̆|̈|̧)|a̋|c(̀|̄|̆|̈|̕|̣|̦|̨̆)|d̂|f(̀|̄)|g̀|h(̄|̦)|j́|k(̀|̂|̄|̇|̕|̛|̦|͟h)|l(̂|̥|̥̄|̦)|m(̀|̂|̆|̐)|n(̂|̄|̆|̦)|p(̀|̄|̕|̣)|r(̆|̥|̥̄)|s(̀|̄|̛̄|̱)|t(̀|̄|̕|̛)|u̇|z(̀|̄|̆|̈|̧)|Ç̆|Û̄|ç̆|û̄|ÿ́|Č(̕|̣)|č(̕|̣)|ē̍|Ī́|ī́|ō̍|Ž(̦|̧)|ž(̦|̧)|Ḳ̄|ḳ̄|Ṣ̄|ṣ̄|Ṭ̄|ṭ̄|Ạ̈|ạ̈|Ọ̈|ọ̈|Ụ(̄|̈)|ụ(̄|̈))*$/";
}

return undefined;
}
10 changes: 7 additions & 3 deletions packages/content/src/attributes/hints/ValueHintsValue.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ISerializable, PrimitiveType, Serializable, serialize, type, validate } from "@js-soft/ts-serval";
import { characterSets } from "../constants/CharacterSets";

export interface ValueHintsValueJSON {
key: string | number | boolean;
Expand All @@ -13,7 +14,7 @@ export interface IValueHintsValue extends ISerializable {
@type("ValueHintsValue")
export class ValueHintsValue extends Serializable implements IValueHintsValue {
@serialize()
@validate({ max: 100 })
@validate({ max: 100, regExp: characterSets.din91379DatatypeC })
public displayName: string;

@validate({
Expand All @@ -28,8 +29,11 @@ export class ValueHintsValue extends Serializable implements IValueHintsValue {
}

private static validateKey(key: string | number | boolean) {
if (typeof key === "string" && key.length > 100) {
return "The maximum length of a key is 200 characters.";
if (typeof key === "string") {
if (key.length > 100) return "The maximum length of a key is 100 characters.";
if (!characterSets.din91379DatatypeC.test(key)) {
return "Value does not match regular expression /^([\\u0009-\\u000A]|\\u000D|[ -~]|[ -¬]|[®-ž]|[Ƈ-ƈ]|Ə|Ɨ|[Ơ-ơ]|[Ư-ư]|Ʒ|[Ǎ-ǜ]|[Ǟ-ǟ]|[Ǣ-ǰ]|[Ǵ-ǵ]|[Ǹ-ǿ]|[Ȓ-ȓ]|[Ș-ț]|[Ȟ-ȟ]|[ȧ-ȳ]|ə|ɨ|ʒ|[ʹ-ʺ]|[ʾ-ʿ]|ˈ|ˌ|[Ḃ-ḃ]|[Ḇ-ḇ]|[Ḋ-ḑ]|ḗ|[Ḝ-ḫ]|[ḯ-ḷ]|[Ḻ-ḻ]|[Ṁ-ṉ]|[Ṓ-ṛ]|[Ṟ-ṣ]|[Ṫ-ṯ]|[Ẁ-ẇ]|[Ẍ-ẗ]|ẞ|[Ạ-ỹ]|’|‡|€|A̋|C(̀|̄|̆|̈|̕|̣|̦|̨̆)|D̂|F(̀|̄)|G̀|H(̄|̦|̱)|J(́|̌)|K(̀|̂|̄|̇|̕|̛|̦|͟H|͟h)|L(̂|̥|̥̄|̦)|M(̀|̂|̆|̐)|N(̂|̄|̆|̦)|P(̀|̄|̕|̣)|R(̆|̥|̥̄)|S(̀|̄|̛̄|̱)|T(̀|̄|̈|̕|̛)|U̇|Z(̀|̄|̆|̈|̧)|a̋|c(̀|̄|̆|̈|̕|̣|̦|̨̆)|d̂|f(̀|̄)|g̀|h(̄|̦)|j́|k(̀|̂|̄|̇|̕|̛|̦|͟h)|l(̂|̥|̥̄|̦)|m(̀|̂|̆|̐)|n(̂|̄|̆|̦)|p(̀|̄|̕|̣)|r(̆|̥|̥̄)|s(̀|̄|̛̄|̱)|t(̀|̄|̕|̛)|u̇|z(̀|̄|̆|̈|̧)|Ç̆|Û̄|ç̆|û̄|ÿ́|Č(̕|̣)|č(̕|̣)|ē̍|Ī́|ī́|ō̍|Ž(̦|̧)|ž(̦|̧)|Ḳ̄|ḳ̄|Ṣ̄|ṣ̄|Ṭ̄|ṭ̄|Ạ̈|ạ̈|Ọ̈|ọ̈|Ụ(̄|̈)|ụ(̄|̈))*$/";
}
}

return undefined;
Expand Down
6 changes: 4 additions & 2 deletions packages/content/src/attributes/types/AbstractString.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { serialize, validate } from "@js-soft/ts-serval";
import { AbstractAttributeValue, AbstractAttributeValueJSON, IAbstractAttributeValue } from "../AbstractAttributeValue";
import { characterSets } from "../constants/CharacterSets";
import { RenderHints, RenderHintsEditType, RenderHintsTechnicalType, ValueHints } from "../hints";

export interface AbstractStringJSON extends AbstractAttributeValueJSON {
Expand All @@ -12,7 +13,7 @@ export interface IAbstractString extends IAbstractAttributeValue {

export class AbstractString extends AbstractAttributeValue implements IAbstractString {
@serialize()
@validate({ max: 100 })
@validate({ max: 100, regExp: characterSets.din91379DatatypeC })
public value: string;

public static override preFrom(value: any): any {
Expand All @@ -26,7 +27,8 @@ export class AbstractString extends AbstractAttributeValue implements IAbstractS

public static get valueHints(): ValueHints {
return ValueHints.from({
max: 100
max: 100,
pattern: characterSets.din91379DatatypeC.toString().slice(1, -1).replaceAll("/", "\\/")
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { serialize, validate } from "@js-soft/ts-serval";
import { nameof } from "ts-simple-nameof";
import { AbstractComplexValue, AbstractComplexValueJSON, IAbstractComplexValue } from "../../AbstractComplexValue";
import { characterSets } from "../../constants/CharacterSets";
import { RenderHints, RenderHintsEditType, RenderHintsTechnicalType, ValueHints } from "../../hints";

export interface AbstractAddressJSON extends AbstractComplexValueJSON {
Expand All @@ -13,13 +14,15 @@ export interface IAbstractAddress extends IAbstractComplexValue {

export abstract class AbstractAddress extends AbstractComplexValue implements IAbstractAddress {
@serialize()
@validate({ max: 100 })
@validate({ max: 100, regExp: characterSets.din91379DatatypeB })
public recipient: string;

public static get valueHints(): ValueHints {
return ValueHints.from({
propertyHints: {
[nameof<AbstractAddress>((a) => a.recipient)]: ValueHints.from({})
[nameof<AbstractAddress>((a) => a.recipient)]: ValueHints.from({
pattern: characterSets.din91379DatatypeB.toString().slice(1, -1).replaceAll("/", "\\/")
})
}
});
}
Expand Down
5 changes: 3 additions & 2 deletions packages/content/src/attributes/types/address/City.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type } from "@js-soft/ts-serval";
import { AbstractString, AbstractStringJSON, IAbstractString } from "../AbstractString";
import { AbstractStringJSON, IAbstractString } from "../AbstractString";
import { AbstractName } from "../strings/AbstractName";

export interface CityJSON extends AbstractStringJSON {
"@type": "City";
Expand All @@ -8,7 +9,7 @@ export interface CityJSON extends AbstractStringJSON {
export interface ICity extends IAbstractString {}

@type("City")
export class City extends AbstractString implements ICity {
export class City extends AbstractName implements ICity {
public static from(value: ICity | Omit<CityJSON, "@type"> | string): City {
return this.fromAny(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { serialize, type, validate } from "@js-soft/ts-serval";
import { nameof } from "ts-simple-nameof";
import { AbstractAttributeValue } from "../../AbstractAttributeValue";
import { COUNTRIES_ALPHA2_TO_ENGLISH_NAME } from "../../constants";
import { characterSets } from "../../constants/CharacterSets";
import { RenderHints, RenderHintsEditType, RenderHintsTechnicalType, ValueHints } from "../../hints";
import { IPhoneNumber, PhoneNumber } from "../communication";
import { AbstractAddress, AbstractAddressJSON, IAbstractAddress } from "./AbstractAddress";
Expand Down Expand Up @@ -34,11 +35,11 @@ export interface IDeliveryBoxAddress extends IAbstractAddress {
@type("DeliveryBoxAddress")
export class DeliveryBoxAddress extends AbstractAddress implements IDeliveryBoxAddress {
@serialize()
@validate({ max: 100 })
@validate({ max: 100, regExp: characterSets.din91379DatatypeB })
public userId: string;

@serialize()
@validate({ max: 100 })
@validate({ max: 100, regExp: characterSets.din91379DatatypeB })
public deliveryBoxId: string;

@serialize({ customGenerator: AbstractAttributeValue.valueGenerator })
Expand All @@ -64,8 +65,8 @@ export class DeliveryBoxAddress extends AbstractAddress implements IDeliveryBoxA
public static override get valueHints(): ValueHints {
return super.valueHints.copyWith({
propertyHints: {
[nameof<DeliveryBoxAddress>((d) => d.userId)]: ValueHints.from({}),
[nameof<DeliveryBoxAddress>((d) => d.deliveryBoxId)]: ValueHints.from({}),
[nameof<DeliveryBoxAddress>((d) => d.userId)]: ValueHints.from({ pattern: characterSets.din91379DatatypeB.toString().slice(1, -1).replaceAll("/", "\\/") }),
[nameof<DeliveryBoxAddress>((d) => d.deliveryBoxId)]: ValueHints.from({ pattern: characterSets.din91379DatatypeB.toString().slice(1, -1).replaceAll("/", "\\/") }),
[nameof<DeliveryBoxAddress>((d) => d.zipCode)]: ZipCode.valueHints,
[nameof<DeliveryBoxAddress>((d) => d.city)]: City.valueHints,
[nameof<DeliveryBoxAddress>((d) => d.country)]: Country.valueHints,
Expand Down
5 changes: 3 additions & 2 deletions packages/content/src/attributes/types/address/HouseNumber.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type } from "@js-soft/ts-serval";
import { AbstractString, AbstractStringJSON, IAbstractString } from "../AbstractString";
import { AbstractStringJSON, IAbstractString } from "../AbstractString";
import { AbstractName } from "../strings/AbstractName";

export interface HouseNumberJSON extends AbstractStringJSON {
"@type": "HouseNumber";
Expand All @@ -8,7 +9,7 @@ export interface HouseNumberJSON extends AbstractStringJSON {
export interface IHouseNumber extends IAbstractString {}

@type("HouseNumber")
export class HouseNumber extends AbstractString implements IHouseNumber {
export class HouseNumber extends AbstractName implements IHouseNumber {
public static from(value: IHouseNumber | Omit<HouseNumberJSON, "@type"> | string): HouseNumber {
return this.fromAny(value);
}
Expand Down
Loading
Loading