mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 00:41:09 +02:00
crypto.randomUUID() requires HTTPS (secure context). Staging uses HTTP, so add fallback using crypto.getRandomValues() which works in insecure contexts. Fallback chain: 1. crypto.randomUUID() - native, requires HTTPS 2. crypto.getRandomValues() - works on HTTP 3. Math.random() - last resort fallback 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
117 lines
3.2 KiB
TypeScript
117 lines
3.2 KiB
TypeScript
import type { DeviceManagerAdapter, DeviceInfo } from '../types';
|
|
|
|
let deviceAdapter: DeviceManagerAdapter | null = null;
|
|
|
|
/**
|
|
* Generate a UUID with fallback for non-secure contexts (HTTP)
|
|
* crypto.randomUUID() requires HTTPS, so we fall back to crypto.getRandomValues()
|
|
*/
|
|
function generateUUID(): string {
|
|
// Try native randomUUID first (requires secure context)
|
|
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
try {
|
|
return crypto.randomUUID();
|
|
} catch {
|
|
// Falls through to fallback
|
|
}
|
|
}
|
|
|
|
// Fallback: use crypto.getRandomValues() which works in insecure contexts
|
|
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
|
|
const bytes = new Uint8Array(16);
|
|
crypto.getRandomValues(bytes);
|
|
|
|
// Set version (4) and variant (RFC 4122)
|
|
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
|
|
// Convert to hex string with dashes
|
|
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
}
|
|
|
|
// Last resort: Math.random() based UUID (not cryptographically secure, but works)
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
const r = (Math.random() * 16) | 0;
|
|
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
return v.toString(16);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Set the device manager adapter for the auth service
|
|
*/
|
|
export function setDeviceAdapter(adapter: DeviceManagerAdapter): void {
|
|
deviceAdapter = adapter;
|
|
}
|
|
|
|
/**
|
|
* Get the current device adapter
|
|
*/
|
|
export function getDeviceAdapter(): DeviceManagerAdapter {
|
|
if (!deviceAdapter) {
|
|
throw new Error(
|
|
'Device adapter not initialized. Call setDeviceAdapter() before using auth services.'
|
|
);
|
|
}
|
|
return deviceAdapter;
|
|
}
|
|
|
|
/**
|
|
* Check if device adapter is initialized
|
|
*/
|
|
export function isDeviceInitialized(): boolean {
|
|
return deviceAdapter !== null;
|
|
}
|
|
|
|
/**
|
|
* Create a web-based device manager adapter
|
|
*/
|
|
export function createWebDeviceAdapter(): DeviceManagerAdapter {
|
|
// Generate a persistent device ID for web
|
|
const getOrCreateDeviceId = (): string => {
|
|
const storageKey = '@manacore/deviceId';
|
|
let deviceId = localStorage.getItem(storageKey);
|
|
if (!deviceId) {
|
|
deviceId = generateUUID();
|
|
localStorage.setItem(storageKey, deviceId);
|
|
}
|
|
return deviceId;
|
|
};
|
|
|
|
return {
|
|
async getDeviceInfo(): Promise<DeviceInfo> {
|
|
const userAgent = navigator.userAgent;
|
|
let deviceName = 'Web Browser';
|
|
let deviceType = 'web';
|
|
|
|
// Try to extract browser name
|
|
if (userAgent.includes('Chrome')) {
|
|
deviceName = 'Chrome Browser';
|
|
} else if (userAgent.includes('Safari')) {
|
|
deviceName = 'Safari Browser';
|
|
} else if (userAgent.includes('Firefox')) {
|
|
deviceName = 'Firefox Browser';
|
|
} else if (userAgent.includes('Edge')) {
|
|
deviceName = 'Edge Browser';
|
|
}
|
|
|
|
// Detect device type
|
|
if (/Mobi|Android/i.test(userAgent)) {
|
|
deviceType = 'mobile_web';
|
|
} else if (/Tablet|iPad/i.test(userAgent)) {
|
|
deviceType = 'tablet_web';
|
|
}
|
|
|
|
return {
|
|
deviceId: getOrCreateDeviceId(),
|
|
deviceName,
|
|
deviceType,
|
|
platform: 'web',
|
|
};
|
|
},
|
|
async getStoredDeviceId(): Promise<string | null> {
|
|
return localStorage.getItem('@manacore/deviceId');
|
|
},
|
|
};
|
|
}
|