feat: add OTP and Passkey Tools to Toolbox 0.11.0

This commit is contained in:
2026-08-19 12:20:27 +02:00
parent 5ed7134d42
commit 0baeda8be8
19 changed files with 188 additions and 41 deletions
+7 -1
View File
@@ -45,6 +45,9 @@ describe('portal UI', () => {
expect(
screen.getByTestId('app-card-de.add-ideas.svg-tools')
).toHaveTextContent('SVG');
expect(
screen.getByTestId('app-card-de.add-ideas.auth-tools')
).toHaveTextContent('OTP & Passkeys');
expect(
screen.queryByText(
'Page-level PDF operations performed locally in the browser.'
@@ -411,6 +414,7 @@ describe('portal UI', () => {
'de.add-ideas.xslt-tools',
'de.add-ideas.onenote-tools',
'de.add-ideas.svg-tools',
'de.add-ideas.auth-tools',
],
hidden: [],
theme: 'light',
@@ -429,6 +433,7 @@ describe('portal UI', () => {
screen.getByTestId('app-card-de.add-ideas.xslt-tools'),
screen.getByTestId('app-card-de.add-ideas.onenote-tools'),
screen.getByTestId('app-card-de.add-ideas.svg-tools'),
screen.getByTestId('app-card-de.add-ideas.auth-tools'),
];
cards.forEach((card, index) => {
const rect = {
@@ -459,7 +464,7 @@ describe('portal UI', () => {
within(tools)
.getAllByRole('heading', { level: 3 })
.map((heading) => heading.textContent)
).toEqual(['XSLT', 'PDF', 'OneNote', 'SVG']);
).toEqual(['XSLT', 'PDF', 'OneNote', 'SVG', 'OTP & Passkeys']);
});
expect(
JSON.parse(localStorage.getItem(PREFERENCES_KEY) ?? '{}').order
@@ -468,6 +473,7 @@ describe('portal UI', () => {
'de.add-ideas.pdf-tools',
'de.add-ideas.onenote-tools',
'de.add-ideas.svg-tools',
'de.add-ideas.auth-tools',
]);
});
+2 -2
View File
@@ -489,9 +489,9 @@ export default function App() {
</span>
</p>
<span>
Portal v0.2.12 ·{' '}
Portal v0.2.13 ·{' '}
<a
href="https://git.add-ideas.de/lotobo/toolbox-portal/src/tag/v0.10.0"
href="https://git.add-ideas.de/lotobo/toolbox-portal/src/tag/v0.11.0"
target="_blank"
rel="noopener noreferrer"
>
+2 -1
View File
@@ -10,7 +10,7 @@ describe('catalogue loading', () => {
const loaded = await loadCatalogue('/toolbox.catalog.json');
expect(loaded.catalogue.name).toBe('add·ideas Toolbox');
expect(loaded.homeUrl).toBe('http://localhost:3000/');
expect(loaded.apps).toHaveLength(4);
expect(loaded.apps).toHaveLength(5);
expect(loaded.apps[0]).toMatchObject({
id: 'de.add-ideas.pdf-tools',
name: 'PDF Workbench',
@@ -41,6 +41,7 @@ describe('catalogue loading', () => {
'de.add-ideas.xslt-tools',
'de.add-ideas.onenote-tools',
'de.add-ideas.svg-tools',
'de.add-ideas.auth-tools',
]);
expect(loaded.unavailable).toHaveLength(1);
expect(loaded.unavailable[0]?.reason).toMatch(/HTTP 404/);
+44
View File
@@ -119,6 +119,47 @@ export const svgManifest: ToolboxAppManifest = {
assets: ['./canvas-frame-controller.js'],
};
export const authManifest: ToolboxAppManifest = {
...pdfManifest,
id: 'de.add-ideas.auth-tools',
name: 'OTP & Passkey Tools',
version: '0.1.0',
description:
'Generate, inspect and verify OTP credentials and test WebAuthn/passkey ceremonies locally in the browser.',
icon: './favicon.svg',
categories: ['security', 'authentication', 'developer'],
tags: [
'otp',
'hotp',
'totp',
'ocra',
'oath',
'webauthn',
'fido2',
'passkey',
'attestation',
'assertion',
],
requirements: {
secureContext: true,
workers: false,
indexedDb: false,
crossOriginIsolated: false,
topLevelContext: true,
},
privacy: {
processing: 'local',
fileUploads: false,
telemetry: false,
label:
'Authentication material stays in this tab; nothing is uploaded or saved unless you explicitly export it.',
},
source: {
repository: 'https://git.add-ideas.de/lotobo/auth-tools',
license: 'GPL-3.0-or-later',
},
};
export const catalogue: ToolboxCatalog = {
schemaVersion: 1,
id: 'de.add-ideas.toolbox',
@@ -130,6 +171,7 @@ export const catalogue: ToolboxCatalog = {
{ manifest: './apps/xslt/toolbox-app.json', enabled: true },
{ manifest: './apps/onenote/toolbox-app.json', enabled: true },
{ manifest: './apps/svg/toolbox-app.json', enabled: true },
{ manifest: './apps/auth/toolbox-app.json', enabled: true },
],
};
@@ -153,6 +195,8 @@ export function catalogueFetch(overrides: Record<string, Response> = {}) {
return Response.json(regexManifest);
if (url.pathname.endsWith('/apps/svg/toolbox-app.json'))
return Response.json(svgManifest);
if (url.pathname.endsWith('/apps/auth/toolbox-app.json'))
return Response.json(authManifest);
return new Response('Not found', { status: 404 });
};
}
+13
View File
@@ -39,4 +39,17 @@ describe('compact tool presentation', () => {
expect(shortToolTitle(svg)).toBe('SVG');
expect(shortToolDescription(svg)).toBe('Inspect and edit vectors locally.');
});
it('uses the compact authentication tile copy', () => {
const auth = app(
'de.add-ideas.auth-tools',
'OTP & Passkey Tools',
'Generate, inspect and verify OTP credentials and test WebAuthn/passkey ceremonies locally in the browser.'
);
expect(shortToolTitle(auth)).toBe('OTP & Passkeys');
expect(shortToolDescription(auth)).toBe(
'Inspect and test authentication locally.'
);
});
});
+4
View File
@@ -25,6 +25,10 @@ const PRESENTATION: Record<string, { title: string; description: string }> = {
title: 'SVG',
description: 'Inspect and edit vectors locally.',
},
'de.add-ideas.auth-tools': {
title: 'OTP & Passkeys',
description: 'Inspect and test authentication locally.',
},
};
export function shortToolTitle(app: ResolvedApp): string {