Skip to content

Commit

Permalink
Added switch for validation of 'invalid' uuids which are valid in oth…
Browse files Browse the repository at this point in the history
…er programming languages (#1365)

Co-authored-by: Oliver Schwendener <[email protected]>
  • Loading branch information
MarcoSennHaag and oliverschwendener authored Feb 14, 2025
1 parent d615cfd commit d3e5a60
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 29 deletions.
1 change: 1 addition & 0 deletions docs/Extensions/UuidGenerator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This extension also allows to format the UUID to several different styles in a f

- **UUID Version**: The UUID version, either [v4](<https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)>), [v6](<https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_1_and_6_(date-time_and_MAC_address)>) or [v7](<https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_7_(timestamp_and_random)>)
- **Number of UUIDs to generate**: The number of UUIDs that will be created, only applies when using the UI of the extension
- **Validate UUIDs strictly**: Whether the UUID should validate correctly (with version and time info) or if it just needs to be in the correct format and hex characters
- **Uppercase**: Whether the characters of the UUID should be uppercase
- **Hyphen**: Whether the UUID should contain hyphens (-)
- **Braces**: Whether the UUID should be wrapped in braces ({})
Expand Down
Binary file modified docs/Extensions/UuidGenerator/example-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { UuidVersion } from "./UuidVersion";
export type UuidGeneratorSetting = {
uuidVersion: UuidVersion;
numberOfUuids: number;
validateStrictly: boolean;
generatorFormat: UuidFormat;
searchResultFormats: UuidFormat[];
};
54 changes: 41 additions & 13 deletions src/main/Extensions/UuidGenerator/UuidGenerator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ describe(UuidGenerator, () => {
describe(UuidGenerator.format, () => {
it("should throw an error if the uuid is invalid", () => {
expect(() =>
UuidGenerator.format("invalid-uuid", {
uppercase: false,
hyphens: false,
braces: false,
quotes: false,
}),
UuidGenerator.format(
"invalid-uuid",
{
uppercase: false,
hyphens: false,
braces: false,
quotes: false,
},
true,
),
).toThrow("Invalid UUID");
});

Expand All @@ -49,21 +53,45 @@ describe(UuidGenerator, () => {
["21771a07-7dce-40b3-850e-386c1a0f5a2d", false, false, false, true, /"[0-9a-f]{32}"/],
["21771a07-7dce-40b3-850e-386c1a0f5a2d", false, false, true, true, /"\{[0-9a-f]{32}\}"/],
])("should format uuid correctly", (uuid, uppercase, hyphens, braces, quotes, expectedPattern) => {
const formattedUuid = UuidGenerator.format(uuid, {
uppercase: uppercase,
hyphens: hyphens,
braces: braces,
quotes: quotes,
});
const formattedUuid = UuidGenerator.format(
uuid,
{
uppercase: uppercase,
hyphens: hyphens,
braces: braces,
quotes: quotes,
},
true,
);
expect(formattedUuid).toMatch(expectedPattern);
});
});

describe(UuidGenerator.validateUuidStrictly, () => {
it.each([
["21771a07-7dce-40b3-850e-386c1a0f5a2d", true],
["21771a07-7dce-40b3-850e-386c1a0f5a2z", false],
["99edf227-d64c-5d90-d314-5d998c38c687", false],
["e4cecde9-9c8e-c386-d314-b0c2d00161ea", false],
["c7dc2472-4d58-7f9d-d314-9568005e9720", false],
["db6b61a3-b22c-0999-d314-c0a53428d3e1", false],
["e9d98550-d8e9-7ab4-d314-a8a540011a47", false],
])("should validate uuid correctly (strict mode)", (uuid, expectedIsValid) => {
const isValid = UuidGenerator.validateUuidStrictly(uuid).toString();
expect(isValid).toMatch(expectedIsValid.toString());
});
});

describe(UuidGenerator.validateUuid, () => {
it.each([
["21771a07-7dce-40b3-850e-386c1a0f5a2d", true],
["21771a07-7dce-40b3-850e-386c1a0f5a2z", false],
])("should validate uuid correctly", (uuid, expectedIsValid) => {
["99edf227-d64c-5d90-d314-5d998c38c687", true],
["e4cecde9-9c8e-c386-d314-b0c2d00161ea", true],
["c7dc2472-4d58-7f9d-d314-9568005e9720", true],
["db6b61a3-b22c-0999-d314-c0a53428d3e1", true],
["e9d98550-d8e9-7ab4-d314-a8a540011a47", true],
])("should validate uuid correctly (not in strict mode)", (uuid, expectedIsValid) => {
const isValid = UuidGenerator.validateUuid(uuid).toString();
expect(isValid).toMatch(expectedIsValid.toString());
});
Expand Down
13 changes: 10 additions & 3 deletions src/main/Extensions/UuidGenerator/UuidGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ export class UuidGenerator {
return uuidv7();
}

public static format(uuid: string, format: UuidFormat): string {
if (!uuidValidate(uuid)) {
public static format(uuid: string, format: UuidFormat, validateStrictly: boolean): string {
if (
(validateStrictly === true && !this.validateUuidStrictly(uuid)) ||
(validateStrictly === false && !this.validateUuid(uuid))
) {
throw new Error("Invalid UUID");
}

Expand Down Expand Up @@ -71,7 +74,11 @@ export class UuidGenerator {
return formattedUuid;
}

public static validateUuid(uuid: string): boolean {
public static validateUuidStrictly(uuid: string): boolean {
return uuidValidate(uuid);
}

public static validateUuid(uuid: string): boolean {
return /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi.test(uuid);
}
}
29 changes: 16 additions & 13 deletions src/main/Extensions/UuidGenerator/UuidGeneratorExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { getExtensionSettingKey } from "@common/Core/Extension";
import type { Image } from "@common/Core/Image";
import type { Resources, Translations } from "@common/Core/Translator";
import type { UuidGeneratorSetting as Settings, UuidFormat, UuidVersion } from "@common/Extensions/UuidGenerator";
import type { UuidGeneratorSetting as Settings, UuidVersion } from "@common/Extensions/UuidGenerator";
import { UuidGenerator } from "./UuidGenerator";

export class UuidGeneratorExtension implements Extension {
Expand All @@ -22,6 +22,7 @@ export class UuidGeneratorExtension implements Extension {
public readonly defaultSettings: Settings = {
uuidVersion: "v4",
numberOfUuids: 10,
validateStrictly: true,
generatorFormat: { uppercase: false, hyphens: true, braces: false, quotes: false },
searchResultFormats: [],
};
Expand All @@ -38,7 +39,8 @@ export class UuidGeneratorExtension implements Extension {
) {}

public getInstantSearchResultItems(searchTerm: string): InstantSearchResultItems {
const uuidFormats: UuidFormat[] = this.getSettingValue("searchResultFormats");
const uuidFormats = this.getSettingValue("searchResultFormats");
const validateStrictly = this.getSettingValue("validateStrictly");

let uuidSearchTerm = searchTerm;
if (uuidSearchTerm.toLowerCase().startsWith("uuid") || uuidSearchTerm.toLowerCase().startsWith("guid")) {
Expand All @@ -56,7 +58,7 @@ export class UuidGeneratorExtension implements Extension {
return {
after: [],
before: uuidFormats.map((format, index) => {
const formattedUuid = UuidGenerator.format(possibleUuid, format);
const formattedUuid = UuidGenerator.format(possibleUuid, format, validateStrictly);

return {
name: formattedUuid,
Expand Down Expand Up @@ -142,6 +144,7 @@ export class UuidGeneratorExtension implements Extension {
openGeneratorName: "UUID / GUID Generator",
uuidVersion: "UUID Version",
numberOfUuids: "Number of UUIDs",
validateStrictly: "Validate UUIDs strictly",
uppercase: "Uppercase",
hyphens: "Hyphens",
braces: "Braces",
Expand All @@ -158,6 +161,7 @@ export class UuidGeneratorExtension implements Extension {
generatorResult: "UUID / GUID",
uuidVersion: "UUID Version",
numberOfUuids: "Anzahl UUIDs",
validateStrictly: "UUIDs strikt validieren",
uppercase: "Grossbuchstaben",
hyphens: "Bindestriche",
braces: "Geschweifte Klammern",
Expand All @@ -180,10 +184,14 @@ export class UuidGeneratorExtension implements Extension {
};
}

public getSettingDefaultValue(key: keyof Settings) {
public getSettingDefaultValue<T extends keyof Settings>(key: T): Settings[T] {
return this.defaultSettings[key];
}

private getSettingValue<T extends keyof Settings>(key: T): Settings[T] {
return this.settingsManager.getValue(getExtensionSettingKey(this.id, key), this.getSettingDefaultValue(key));
}

public async invoke(settings: Settings): Promise<string[]> {
const result = [];
for (let index = 0; index < settings.numberOfUuids; index++) {
Expand Down Expand Up @@ -225,17 +233,12 @@ export class UuidGeneratorExtension implements Extension {
}
}

return UuidGenerator.format(uuid, { uppercase, hyphens, braces, quotes });
}

private getSettingValue<T>(key: keyof Settings): T {
return this.settingsManager.getValue<T>(
getExtensionSettingKey(this.id, key),
<T>this.getSettingDefaultValue(key),
);
return UuidGenerator.format(uuid, { uppercase, hyphens, braces, quotes }, true);
}

private validateUuid(uuid: string): boolean {
return UuidGenerator.validateUuid(uuid);
return this.getSettingValue("validateStrictly") === true
? UuidGenerator.validateUuidStrictly(uuid)
: UuidGenerator.validateUuid(uuid);
}
}
6 changes: 6 additions & 0 deletions src/renderer/Extensions/UuidGenerator/Generator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export const Generator = ({
key: "numberOfUuids",
});

const { value: validateStrictly } = useExtensionSetting<boolean>({
extensionId,
key: "validateStrictly",
});

const { value: uppercase, updateValue: setUppercase } = useExtensionSetting<boolean>({
extensionId,
key: "uppercase",
Expand Down Expand Up @@ -71,6 +76,7 @@ export const Generator = ({
const uuids = await contextBridge.invokeExtension<UuidGeneratorSetting, InvocationResult>(extensionId, {
uuidVersion: uuidVersion,
numberOfUuids: numberOfUuids,
validateStrictly: validateStrictly,
generatorFormat: {
uppercase: uppercase,
hyphens: hyphens,
Expand Down
15 changes: 15 additions & 0 deletions src/renderer/Extensions/UuidGenerator/UuidGeneratorSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Input,
Label,
Option,
Switch,
Table,
TableBody,
TableCell,
Expand Down Expand Up @@ -40,6 +41,11 @@ export const UuidGeneratorSettings = () => {
key: "numberOfUuids",
});

const { value: validateStrictly, updateValue: setValidateStrictly } = useExtensionSetting<boolean>({
extensionId,
key: "validateStrictly",
});

const { value: uppercase, updateValue: setUppercase } = useExtensionSetting<boolean>({
extensionId,
key: "uppercase",
Expand Down Expand Up @@ -124,6 +130,15 @@ export const UuidGeneratorSettings = () => {
/>
}
/>
<Setting
label={t("validateStrictly")}
control={
<Switch
checked={validateStrictly}
onChange={(_, { checked }) => setValidateStrictly(checked)}
/>
}
/>
<div style={{ paddingTop: 8 }}>
<Label weight="semibold">{t("defaultGeneratorFormat")}</Label>
</div>
Expand Down

0 comments on commit d3e5a60

Please sign in to comment.