diff --git a/package-lock.json b/package-lock.json index 824c8961b..58b848505 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12399,7 +12399,7 @@ }, "packages/content": { "name": "@nmshd/content", - "version": "2.10.1", + "version": "2.10.2", "license": "MIT", "dependencies": { "@js-soft/logging-abstractions": "^1.0.1", @@ -12432,7 +12432,7 @@ "@js-soft/ts-serval": "2.0.10", "@js-soft/ts-utils": "^2.3.3", "@nmshd/consumption": "3.11.0", - "@nmshd/content": "2.10.1", + "@nmshd/content": "2.10.2", "@nmshd/crypto": "2.0.6", "@nmshd/transport": "2.8.0", "ajv": "^8.16.0", diff --git a/packages/content/package.json b/packages/content/package.json index f908cd341..ec0d535d1 100644 --- a/packages/content/package.json +++ b/packages/content/package.json @@ -1,6 +1,6 @@ { "name": "@nmshd/content", - "version": "2.10.1", + "version": "2.10.2", "description": "The content library defines data structures that can be transmitted using the transport library.", "homepage": "https://enmeshed.eu", "repository": { diff --git a/packages/content/src/attributes/types/strings/AbstractEMailAddress.ts b/packages/content/src/attributes/types/strings/AbstractEMailAddress.ts index e374d9870..db1858576 100644 --- a/packages/content/src/attributes/types/strings/AbstractEMailAddress.ts +++ b/packages/content/src/attributes/types/strings/AbstractEMailAddress.ts @@ -4,19 +4,22 @@ import { AbstractString } from "../AbstractString"; export abstract class AbstractEMailAddress extends AbstractString { // from https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address + private static readonly regExp = new RegExp( + /^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@([A-Za-z0-9ÄäÖöÜüß]([A-Za-z0-9ÄäÖöÜüß-]{0,61}[A-Za-z0-9ÄäÖöÜüß])?\.)+[A-Za-z0-9ÄäÖöÜüß][A-Za-z0-9ÄäÖöÜüß-]{0,61}[A-Za-z0-9ÄäÖöÜüß]$/ + ); @serialize() @validate({ min: 3, - max: 100, - regExp: new RegExp("^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}$", "i") + max: 254, + regExp: AbstractEMailAddress.regExp }) public override value: string; public static override get valueHints(): ValueHints { return super.valueHints.copyWith({ min: 3, - max: 100, - pattern: "/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}$/i" + max: 254, + pattern: String(AbstractEMailAddress.regExp) }); } diff --git a/packages/content/src/attributes/types/strings/AbstractURL.ts b/packages/content/src/attributes/types/strings/AbstractURL.ts index 65dbaf13f..5b7619fe7 100644 --- a/packages/content/src/attributes/types/strings/AbstractURL.ts +++ b/packages/content/src/attributes/types/strings/AbstractURL.ts @@ -3,14 +3,15 @@ import { RenderHints, RenderHintsDataType, RenderHintsEditType, ValueHints } fro import { AbstractString } from "../AbstractString"; export abstract class AbstractURL extends AbstractString { + private static readonly regExp = new RegExp( + /^([A-Za-z]+:\/\/)?((www\.)|(?!www\.))([A-Za-z0-9ÄäÖöÜüß]([A-Za-zÄäÖöÜüß0-9-]{0,61}[A-Za-zÄäÖöÜüß0-9])?\.)+([A-Za-z0-9ÄäÖöÜüß]([A-Za-zÄäÖöÜüß0-9-]{0,61}[A-Za-zÄäÖöÜüß0-9])?)(:[0-9]+)?(\/[A-Za-zÄäÖöÜüß0-9?#@!$&'()*+,;=%-]*)*$/ + ); + @serialize() @validate({ min: 3, max: 1024, - regExp: new RegExp( - // eslint-disable-next-line no-useless-escape - /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/ - ) + regExp: AbstractURL.regExp }) public override value: string; @@ -18,8 +19,7 @@ export abstract class AbstractURL extends AbstractString { return super.valueHints.copyWith({ min: 3, max: 1024, - pattern: - "/((([A-Za-z]{3,9}:(?:\\/\\/)?)(?:[-;:&=\\+\\$,\\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\\+\\$,\\w]+@)[A-Za-z0-9.-]+)((?:\\/[\\+~%\\/.\\w\\-_]*)?\\??(?:[-\\+=&;%@.\\w_]*)#?(?:[\\w]*))?)/" + pattern: String(AbstractURL.regExp) }); } diff --git a/packages/content/test/attributes/EMailAddress.test.ts b/packages/content/test/attributes/EMailAddress.test.ts new file mode 100644 index 000000000..ddf22e0bf --- /dev/null +++ b/packages/content/test/attributes/EMailAddress.test.ts @@ -0,0 +1,38 @@ +import { ParsingError } from "@js-soft/ts-serval"; +import { EMailAddress } from "../../src"; + +describe("Test valid EMailAddresses", () => { + const validEMailAddresses = ["peter123@inwind.it", "peter123@inwänd.it"]; + + test.each(validEMailAddresses)("EMail %s is recognized as valid", (email) => { + const validEMailAddress = EMailAddress.from({ value: email }); + expect(validEMailAddress.value.toString()).toBe(email); + }); +}); + +describe("Test invalid EMailAddresses", () => { + const invalidEMailAddresses = ["Hugo Becker@gmx.de", "Becker@gmx", "Becker@gmx-.de", "Becker@gmx-.de", ".Becker@gmx.de", "test@.address", "test@test..address"]; + + test.each(invalidEMailAddresses)("EMail %s is recognized as invalid", (email) => { + const invalidEMailAddressCall = () => { + EMailAddress.from({ + value: email + }); + }; + expect(invalidEMailAddressCall).toThrow( + new ParsingError( + "EMailAddress", + "value", + "Value does not match regular expression /^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@([A-Za-z0-9ÄäÖöÜüß]([A-Za-z0-9ÄäÖöÜüß-]{0,61}[A-Za-z0-9ÄäÖöÜüß])?\\.)+[A-Za-z0-9ÄäÖöÜüß][A-Za-z0-9ÄäÖöÜüß-]{0,61}[A-Za-z0-9ÄäÖöÜüß]$/" + ) + ); + }); + test("returns an error when trying to create an Attribute Value Type EMailAddress wich is empty", function () { + const invalidEMailAddressCall = () => { + EMailAddress.from({ + value: "" + }); + }; + expect(invalidEMailAddressCall).toThrow(new ParsingError("EMailAddress", "value", "Value is shorter than 3 characters")); + }); +}); diff --git a/packages/content/test/attributes/Website.test.ts b/packages/content/test/attributes/Website.test.ts new file mode 100644 index 000000000..53fba0c46 --- /dev/null +++ b/packages/content/test/attributes/Website.test.ts @@ -0,0 +1,45 @@ +import { ParsingError } from "@js-soft/ts-serval"; +import { Website } from "../../src"; + +describe("Test valid URLs", () => { + const validUrls = [ + "www.google.com", + "https://inwänd.it", + "http://inwind.it", + "https://enmeshed.de/blog/meilenstein-enmeshed-als-komponente-ablage-in-mein-bildungsraum-geht-in-die-testphase-der-beta-version/", + "www.foo.www.www.enmeshed.eu", + "https://example.org:8080/mein/ordner/bericht" + ]; + + test.each(validUrls)("URL %s is recognized as valid", (url) => { + const validWebsite = Website.from({ value: url }); + expect(validWebsite.value.toString()).toBe(url); + }); +}); + +describe("Test invalid URLs", () => { + const invalidUrls = ["google-.de", "www.google", "www.-google", "https://inwind.test it"]; + + test.each(invalidUrls)("URL %s is recognized as invalid", (url) => { + const invalidWebsiteCall = () => { + Website.from({ + value: url + }); + }; + expect(invalidWebsiteCall).toThrow( + new ParsingError( + "Website", + "value", + "Value does not match regular expression /^([A-Za-z]+:\\/\\/)?((www\\.)|(?!www\\.))([A-Za-z0-9ÄäÖöÜüß]([A-Za-zÄäÖöÜüß0-9-]{0,61}[A-Za-zÄäÖöÜüß0-9])?\\.)+([A-Za-z0-9ÄäÖöÜüß]([A-Za-zÄäÖöÜüß0-9-]{0,61}[A-Za-zÄäÖöÜüß0-9])?)(:[0-9]+)?(\\/[A-Za-zÄäÖöÜüß0-9?#@!$&'()*+,;=%-]*)*$/" + ) + ); + }); + test("returns an error when trying to create an Attribute Value Type Website wich is empty", function () { + const invalidWebsiteCall = () => { + Website.from({ + value: "" + }); + }; + expect(invalidWebsiteCall).toThrow(new ParsingError("Website", "value", "Value is shorter than 3 characters")); + }); +}); diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 708811560..4564cae23 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -57,7 +57,7 @@ "@js-soft/ts-serval": "2.0.10", "@js-soft/ts-utils": "^2.3.3", "@nmshd/consumption": "3.11.0", - "@nmshd/content": "2.10.1", + "@nmshd/content": "2.10.2", "@nmshd/crypto": "2.0.6", "@nmshd/transport": "2.8.0", "ajv": "^8.16.0",