diff --git a/package-lock.json b/package-lock.json index 7e558688..f8ee1c25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "plugins/*" ], "dependencies": { - "@yaakapp/api": "^0.5.3" + "@yaakapp/api": "^0.6.0" }, "devDependencies": { "@types/node": "^22.7.4", @@ -999,9 +999,9 @@ } }, "node_modules/@yaakapp/api": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@yaakapp/api/-/api-0.5.3.tgz", - "integrity": "sha512-JKO0t5H+wM2KWpNgiNW5UVmk66c7p2WFCHa8TnLwnkFpub/3ktZfMY1Y+c21N2gsurqUe3wmcNRM0J1nQrR9rA==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@yaakapp/api/-/api-0.6.0.tgz", + "integrity": "sha512-7DELi/E5Ayx+lmWSYVhjgE4Ll+hf7IWPnbFMkYhO7G14nk2WIjTeDdoAA3/7XMi5M4cL8+GGsx9mYXmts9YP7g==", "dependencies": { "@types/node": "^22.5.4" } @@ -1054,6 +1054,14 @@ "resolved": "plugins/importer-yaak", "link": true }, + "node_modules/@yaakapp/template-function-cookie": { + "resolved": "plugins/template-function-cookie", + "link": true + }, + "node_modules/@yaakapp/template-function-encode": { + "resolved": "plugins/template-function-encode", + "link": true + }, "node_modules/@yaakapp/template-function-fs": { "resolved": "plugins/template-function-fs", "link": true @@ -1066,6 +1074,10 @@ "resolved": "plugins/template-function-prompt", "link": true }, + "node_modules/@yaakapp/template-function-regex": { + "resolved": "plugins/template-function-regex", + "link": true + }, "node_modules/@yaakapp/template-function-request": { "resolved": "plugins/template-function-request", "link": true @@ -7190,6 +7202,14 @@ "name": "@yaakapp/importer-yaak", "version": "0.0.1" }, + "plugins/template-function-cookie": { + "name": "@yaakapp/template-function-cookie", + "version": "0.0.1" + }, + "plugins/template-function-encode": { + "name": "@yaakapp/template-function-encode", + "version": "0.0.1" + }, "plugins/template-function-file": { "name": "@yaakapp/template-function-file", "version": "0.0.1", @@ -7207,6 +7227,10 @@ "name": "@yaakapp/template-function-prompt", "version": "0.0.1" }, + "plugins/template-function-regex": { + "name": "@yaakapp/template-function-regex", + "version": "0.0.1" + }, "plugins/template-function-request": { "name": "@yaakapp/template-function-request", "version": "0.0.1" diff --git a/package.json b/package.json index 882533ab..a0da177c 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,6 @@ "workspaces-run": "^1.0.2" }, "dependencies": { - "@yaakapp/api": "^0.5.3" + "@yaakapp/api": "^0.6.0" } } diff --git a/plugins/auth-oauth2/src/index.ts b/plugins/auth-oauth2/src/index.ts index 731bf291..9026a305 100644 --- a/plugins/auth-oauth2/src/index.ts +++ b/plugins/auth-oauth2/src/index.ts @@ -115,7 +115,6 @@ export const plugin: PluginDefinition = { label: 'Client ID', optional: true, }, - { type: 'text', name: 'clientSecret', diff --git a/plugins/template-function-cookie/package.json b/plugins/template-function-cookie/package.json new file mode 100644 index 00000000..1473c0b2 --- /dev/null +++ b/plugins/template-function-cookie/package.json @@ -0,0 +1,9 @@ +{ + "name": "@yaakapp/template-function-cookie", + "private": true, + "version": "0.0.1", + "scripts": { + "build": "yaakcli build ./src/index.ts", + "dev": "yaakcli dev ./src/index.js" + } +} diff --git a/plugins/template-function-cookie/src/index.ts b/plugins/template-function-cookie/src/index.ts new file mode 100644 index 00000000..3d39d74c --- /dev/null +++ b/plugins/template-function-cookie/src/index.ts @@ -0,0 +1,20 @@ +import { CallTemplateFunctionArgs, Context, PluginDefinition } from '@yaakapp/api'; + +export const plugin: PluginDefinition = { + templateFunctions: [ + { + name: 'cookie.value', + description: 'Read the value of a cookie in the jar, by name', + args: [ + { + type: 'text', + name: 'cookie_name', + label: 'Cookie Name', + }, + ], + async onRender(ctx: Context, args: CallTemplateFunctionArgs): Promise { + return ctx.cookies.getValue({ name: String(args.values.cookie_name) }); + }, + }, + ], +}; diff --git a/plugins/template-function-encode/package.json b/plugins/template-function-encode/package.json new file mode 100644 index 00000000..4c261fdc --- /dev/null +++ b/plugins/template-function-encode/package.json @@ -0,0 +1,9 @@ +{ + "name": "@yaakapp/template-function-encode", + "private": true, + "version": "0.0.1", + "scripts": { + "build": "yaakcli build ./src/index.ts", + "dev": "yaakcli dev ./src/index.js" + } +} diff --git a/plugins/template-function-encode/src/index.ts b/plugins/template-function-encode/src/index.ts new file mode 100644 index 00000000..15bb985b --- /dev/null +++ b/plugins/template-function-encode/src/index.ts @@ -0,0 +1,22 @@ +import { CallTemplateFunctionArgs, Context, PluginDefinition } from '@yaakapp/api'; + +export const plugin: PluginDefinition = { + templateFunctions: [ + { + name: 'base64.encode', + description: 'Encode a value to base64', + args: [{ label: 'Plain Text', type: 'text', name: 'value', multiLine: true }], + async onRender(_ctx: Context, args: CallTemplateFunctionArgs): Promise { + return Buffer.from(args.values.value ?? '').toString('base64'); + }, + }, + { + name: 'base64.decode', + description: 'Decode a value from base64', + args: [{ label: 'Encoded Value', type: 'text', name: 'value', multiLine: true }], + async onRender(_ctx: Context, args: CallTemplateFunctionArgs): Promise { + return Buffer.from(args.values.value ?? '', 'base64').toString('utf-8'); + }, + }, + ], +}; diff --git a/plugins/template-function-hash/src/index.ts b/plugins/template-function-hash/src/index.ts index 9fca36a4..308cb0aa 100755 --- a/plugins/template-function-hash/src/index.ts +++ b/plugins/template-function-hash/src/index.ts @@ -1,25 +1,86 @@ import { CallTemplateFunctionArgs, Context, PluginDefinition } from '@yaakapp/api'; -import { createHash } from 'node:crypto'; +import { createHash, createHmac } from 'node:crypto'; -const algorithms = ['md5', 'sha1', 'sha256', 'sha512']; +const algorithms = ['md5', 'sha1', 'sha256', 'sha512'] as const; +const encodings = ['base64', 'hex'] as const; + +type TemplateFunctionPlugin = NonNullable[number]; + +const hashFunctions: TemplateFunctionPlugin[] = algorithms.map(algorithm => ({ + name: `hash.${algorithm}`, + description: 'Hash a value to its hexidecimal representation', + args: [ + { + type: 'text', + name: 'input', + label: 'Input', + placeholder: 'input text', + multiLine: true, + }, + { + type: 'select', + name: 'encoding', + label: 'Encoding', + defaultValue: 'base64', + options: encodings.map(encoding => ({ + label: capitalize(encoding), + value: encoding, + })), + }, + ], + async onRender(_ctx: Context, args: CallTemplateFunctionArgs): Promise { + const input = String(args.values.input); + const encoding = String(args.values.encoding) as typeof encodings[number]; + + return createHash(algorithm) + .update(input, 'utf-8') + .digest(encoding); + }, +})); + +const hmacFunctions: TemplateFunctionPlugin[] = algorithms.map(algorithm => ({ + name: `hmac.${algorithm}`, + description: 'Compute the HMAC of a value', + args: [ + { + type: 'text', + name: 'input', + label: 'Input', + placeholder: 'input text', + multiLine: true, + }, + { + type: 'text', + name: 'key', + label: 'Key', + password: true, + }, + { + type: 'select', + name: 'encoding', + label: 'Encoding', + defaultValue: 'base64', + options: encodings.map(encoding => ({ + value: encoding, + label: capitalize(encoding), + })), + }, + ], + async onRender(_ctx: Context, args: CallTemplateFunctionArgs): Promise { + const input = String(args.values.input); + const key = String(args.values.key); + const encoding = String(args.values.encoding) as typeof encodings[number]; + + return createHmac(algorithm, key, {}) + .update(input) + .digest(encoding); + }, +})); export const plugin: PluginDefinition = { - templateFunctions: algorithms.map(algorithm => ({ - name: `hash.${algorithm}`, - description: 'Hash a value to its hexidecimal representation', - args: [ - { - name: 'input', - label: 'Input', - placeholder: 'input text', - type: 'text', - }, - ], - async onRender(_ctx: Context, args: CallTemplateFunctionArgs): Promise { - if (!args.values.input) return ''; - return createHash(algorithm) - .update(args.values.input, 'utf-8') - .digest('hex'); - }, - })), + templateFunctions: [...hashFunctions, ...hmacFunctions], }; + +function capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); +} diff --git a/plugins/template-function-regex/package.json b/plugins/template-function-regex/package.json new file mode 100644 index 00000000..de67316b --- /dev/null +++ b/plugins/template-function-regex/package.json @@ -0,0 +1,9 @@ +{ + "name": "@yaakapp/template-function-regex", + "private": true, + "version": "0.0.1", + "scripts": { + "build": "yaakcli build ./src/index.ts", + "dev": "yaakcli dev ./src/index.js" + } +} diff --git a/plugins/template-function-regex/src/index.ts b/plugins/template-function-regex/src/index.ts new file mode 100644 index 00000000..a62367cc --- /dev/null +++ b/plugins/template-function-regex/src/index.ts @@ -0,0 +1,28 @@ +import { CallTemplateFunctionArgs, Context, PluginDefinition } from '@yaakapp/api'; + +export const plugin: PluginDefinition = { + templateFunctions: [{ + name: 'regex.match', + description: 'Extract', + args: [ + { + type: 'text', + name: 'regex', + label: 'Regular Expression', + placeholder: '^\w+=(?\w*)$', + defaultValue: '^(.*)$', + description: 'A JavaScript regular expression, evaluated using the Node.js RegExp engine. Capture groups or named groups can be used to extract values.', + }, + { type: 'text', name: 'input', label: 'Input Text', multiLine: true }, + ], + async onRender(_ctx: Context, args: CallTemplateFunctionArgs): Promise { + if (!args.values.regex) return ''; + + const regex = new RegExp(String(args.values.regex)); + const match = args.values.input?.match(regex); + return match?.groups + ? Object.values(match.groups)[0] ?? '' + : match?.[1] ?? match?.[0] ?? ''; + }, + }], +};