summaryrefslogtreecommitdiff
path: root/src/digiid.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/digiid.ts')
-rw-r--r--src/digiid.ts55
1 files changed, 55 insertions, 0 deletions
diff --git a/src/digiid.ts b/src/digiid.ts
new file mode 100644
index 0000000..6322403
--- /dev/null
+++ b/src/digiid.ts
@@ -0,0 +1,55 @@
+import { randomBytes } from 'crypto';
+import { DigiIDUriOptions, DigiIDError } from './types';
+
+/**
+ * Generates a secure random nonce (hex string).
+ * @param length - The number of bytes to generate (default: 16, resulting in 32 hex chars).
+ * @returns A hex-encoded random string.
+ */
+function generateNonce(length = 16): string {
+ return randomBytes(length).toString('hex');
+}
+
+/**
+ * Generates a DigiID authentication URI.
+ *
+ * @param options - Options for URI generation, including the callback URL.
+ * @returns The generated DigiID URI string.
+ * @throws {DigiIDError} If the callback URL is invalid or missing.
+ */
+export function generateDigiIDUri(options: DigiIDUriOptions): string {
+ if (!options.callbackUrl) {
+ throw new DigiIDError('Callback URL is required.');
+ }
+
+ let parsedUrl: URL;
+ try {
+ parsedUrl = new URL(options.callbackUrl);
+ } catch (e) {
+ throw new DigiIDError(`Invalid callback URL: ${(e as Error).message}`);
+ }
+
+ // DigiID spec requires stripping the scheme (http/https)
+ const domainAndPath = parsedUrl.host + parsedUrl.pathname;
+
+ const nonce = options.nonce || generateNonce();
+ const unsecureFlag = options.unsecure ? '1' : '0'; // 1 for http, 0 for https
+
+ // Validate scheme based on unsecure flag
+ if (options.unsecure && parsedUrl.protocol !== 'http:') {
+ throw new DigiIDError('Unsecure flag is true, but callback URL does not use http protocol.');
+ }
+ if (!options.unsecure && parsedUrl.protocol !== 'https:') {
+ throw new DigiIDError('Callback URL must use https protocol unless unsecure flag is set to true.');
+ }
+
+ // Construct the URI
+ // Example: digiid://example.com/callback?x=nonce_value&u=0
+ const uri = `digiid://${domainAndPath}?x=${nonce}&u=${unsecureFlag}`;
+
+ // Clean up potential trailing slash in path if no query params exist (though DigiID always has params)
+ // This check might be redundant given DigiID structure, but good practice
+ // const cleanedUri = uri.endsWith('/') && parsedUrl.search === '' ? uri.slice(0, -1) : uri;
+
+ return uri;
+}