mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
@@ -0,0 +1,16 @@
|
||||
[tool.commitizen]
|
||||
name = "cz_customize"
|
||||
tag_format = "pkg-sdk/v$version"
|
||||
ignored_tag_formats = ["*/v${version}", "v${version}"]
|
||||
version_scheme = "semver"
|
||||
version_provider = "npm"
|
||||
update_changelog_on_bump = true
|
||||
major_version_zero = true
|
||||
pre_bump_hooks = ["bash ../../scripts/hook-bump-pre.sh"]
|
||||
post_bump_hooks = ["pnpm --filter '@sonr.io/sdk' publish --no-git-checks"]
|
||||
|
||||
[tool.commitizen.customize]
|
||||
bump_pattern = "^(feat|fix|refactor|perf|BREAKING CHANGE)"
|
||||
bump_map = { "BREAKING CHANGE" = "MAJOR", "feat" = "MINOR", "fix" = "PATCH", "refactor" = "PATCH", "perf" = "PATCH" }
|
||||
default_bump = "PATCH"
|
||||
changelog_pattern = "^(feat|fix|refactor|docs|build)\\(pkg-sdk\\)(!)?:"
|
||||
@@ -0,0 +1,298 @@
|
||||
# @sonr.io/sdk
|
||||
|
||||
This is the TypeScript SDK for Highway WebAuthn authentication gateway. It provides a comprehensive client library for interacting with Highway APIs, including WebAuthn authentication, session management, and blockchain operations.
|
||||
|
||||
## Features
|
||||
|
||||
- **WebAuthn Client**: Complete WebAuthn registration and authentication flows
|
||||
- **Session Management**: Automatic session handling and token management
|
||||
- **Type Safety**: Full TypeScript support with comprehensive type definitions
|
||||
- **HTTP Client**: Configured HTTP client with automatic retries and error handling
|
||||
- **Blockchain Integration**: Client methods for DID and blockchain operations
|
||||
- **Environment Support**: Configurable for development, staging, and production
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @sonr.io/sdk
|
||||
# or
|
||||
yarn add @sonr.io/sdk
|
||||
# or
|
||||
pnpm add @sonr.io/sdk
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Setup
|
||||
|
||||
```typescript
|
||||
import { HighwaySDK } from "@sonr.io/sdk";
|
||||
|
||||
const sdk = new HighwaySDK({
|
||||
apiUrl: "https://api.yourdomain.com",
|
||||
environment: "production",
|
||||
});
|
||||
```
|
||||
|
||||
### WebAuthn Authentication
|
||||
|
||||
```typescript
|
||||
// Register a new user
|
||||
try {
|
||||
const registrationResult = await sdk.auth.register({
|
||||
username: "user@example.com",
|
||||
displayName: "John Doe",
|
||||
});
|
||||
|
||||
console.log("Registration successful:", registrationResult);
|
||||
} catch (error) {
|
||||
console.error("Registration failed:", error);
|
||||
}
|
||||
|
||||
// Authenticate existing user
|
||||
try {
|
||||
const authResult = await sdk.auth.authenticate({
|
||||
username: "user@example.com",
|
||||
});
|
||||
|
||||
console.log("Authentication successful:", authResult);
|
||||
} catch (error) {
|
||||
console.error("Authentication failed:", error);
|
||||
}
|
||||
```
|
||||
|
||||
### Session Management
|
||||
|
||||
```typescript
|
||||
// Get current session
|
||||
const session = await sdk.session.getCurrent();
|
||||
|
||||
// Validate session
|
||||
const isValid = await sdk.session.validate();
|
||||
|
||||
// Logout
|
||||
await sdk.session.logout();
|
||||
```
|
||||
|
||||
### Blockchain Operations
|
||||
|
||||
```typescript
|
||||
// Create DID
|
||||
const didResult = await sdk.blockchain.createDID({
|
||||
username: "user@example.com",
|
||||
credentialId: "webauthn-credential-id",
|
||||
publicKey: "public-key-data",
|
||||
});
|
||||
|
||||
// Resolve DID
|
||||
const didDocument = await sdk.blockchain.resolveDID("did:sonr:123456789");
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### HighwaySDK
|
||||
|
||||
The main SDK class that provides access to all Highway services.
|
||||
|
||||
#### Constructor Options
|
||||
|
||||
```typescript
|
||||
interface HighwaySDKOptions {
|
||||
apiUrl: string;
|
||||
environment?: "development" | "staging" | "production";
|
||||
timeout?: number;
|
||||
retries?: number;
|
||||
}
|
||||
```
|
||||
|
||||
#### Methods
|
||||
|
||||
- `auth`: WebAuthn authentication methods
|
||||
- `session`: Session management methods
|
||||
- `blockchain`: Blockchain and DID operations
|
||||
- `profile`: User profile management
|
||||
|
||||
### Authentication (`sdk.auth`)
|
||||
|
||||
- `register(options)`: Register new WebAuthn credential
|
||||
- `authenticate(options)`: Authenticate with WebAuthn
|
||||
- `getProfile()`: Get current user profile
|
||||
|
||||
### Session (`sdk.session`)
|
||||
|
||||
- `getCurrent()`: Get current session information
|
||||
- `validate()`: Validate current session
|
||||
- `logout()`: End current session
|
||||
|
||||
### Blockchain (`sdk.blockchain`)
|
||||
|
||||
- `createDID(options)`: Create new DID document
|
||||
- `resolveDID(id)`: Resolve DID document by ID
|
||||
- `getHealth()`: Get blockchain service health
|
||||
|
||||
## Development Roadmap
|
||||
|
||||
### 🔮 **Future Implementation** (Planned)
|
||||
|
||||
- [ ] **SDK Core**: TypeScript SDK with HTTP client configuration
|
||||
- [ ] **Authentication Module**: WebAuthn registration and authentication methods
|
||||
- [ ] **Session Management**: Automatic session handling and token management
|
||||
- [ ] **Blockchain Module**: DID creation and resolution methods
|
||||
- [ ] **Profile Management**: User profile operations and management
|
||||
- [ ] **Type Definitions**: Comprehensive TypeScript type definitions
|
||||
- [ ] **Error Handling**: Robust error handling and retry logic
|
||||
|
||||
### 🚧 **Production Readiness** (Next)
|
||||
|
||||
- [ ] **Testing Suite**: Unit tests for all SDK methods
|
||||
- [ ] **Documentation**: Complete API documentation and examples
|
||||
- [ ] **Performance Optimization**: Request caching and optimization
|
||||
- [ ] **Bundle Optimization**: Tree-shaking and minimal bundle size
|
||||
- [ ] **Browser Support**: Cross-browser compatibility testing
|
||||
- [ ] **Node.js Support**: Server-side usage support
|
||||
|
||||
### 🔮 **Future Enhancements**
|
||||
|
||||
- [ ] **React Hooks**: React hooks for easy integration
|
||||
- [ ] **Vue Composables**: Vue.js composables for Vue applications
|
||||
- [ ] **Offline Support**: Offline capability with background sync
|
||||
- [ ] **Real-time Features**: WebSocket support for real-time updates
|
||||
- [ ] **Advanced Caching**: Intelligent caching strategies
|
||||
- [ ] **Plugin System**: Extensible plugin architecture
|
||||
|
||||
## Error Handling
|
||||
|
||||
The SDK provides comprehensive error handling:
|
||||
|
||||
```typescript
|
||||
import { HighwayError, WebAuthnError, SessionError } from "@sonr.io/sdk";
|
||||
|
||||
try {
|
||||
await sdk.auth.register(options);
|
||||
} catch (error) {
|
||||
if (error instanceof WebAuthnError) {
|
||||
console.error("WebAuthn error:", error.message);
|
||||
} else if (error instanceof SessionError) {
|
||||
console.error("Session error:", error.message);
|
||||
} else if (error instanceof HighwayError) {
|
||||
console.error("Highway error:", error.message);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```env
|
||||
# Default API URL
|
||||
HIGHWAY_API_URL=https://api.yourdomain.com
|
||||
|
||||
# Development
|
||||
HIGHWAY_API_URL=http://localhost:8080
|
||||
```
|
||||
|
||||
### SDK Configuration
|
||||
|
||||
```typescript
|
||||
const sdk = new HighwaySDK({
|
||||
apiUrl: process.env.HIGHWAY_API_URL || "https://api.yourdomain.com",
|
||||
environment: process.env.NODE_ENV || "production",
|
||||
timeout: 10000,
|
||||
retries: 3,
|
||||
});
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
pnpm install
|
||||
|
||||
# Build the SDK
|
||||
pnpm build
|
||||
|
||||
# Run tests
|
||||
pnpm test
|
||||
|
||||
# Run tests in watch mode
|
||||
pnpm test:watch
|
||||
```
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### React Application
|
||||
|
||||
```typescript
|
||||
import { HighwaySDK } from "@sonr.io/sdk";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function useHighway() {
|
||||
const [sdk] = useState(
|
||||
() =>
|
||||
new HighwaySDK({
|
||||
apiUrl: process.env.NEXT_PUBLIC_API_URL!,
|
||||
})
|
||||
);
|
||||
|
||||
return sdk;
|
||||
}
|
||||
|
||||
function AuthComponent() {
|
||||
const sdk = useHighway();
|
||||
|
||||
const handleRegister = async () => {
|
||||
try {
|
||||
await sdk.auth.register({
|
||||
username: "user@example.com",
|
||||
displayName: "John Doe",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Registration failed:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return <button onClick={handleRegister}>Register with WebAuthn</button>;
|
||||
}
|
||||
```
|
||||
|
||||
### Node.js Application
|
||||
|
||||
```typescript
|
||||
import { HighwaySDK } from "@sonr.io/sdk";
|
||||
|
||||
const sdk = new HighwaySDK({
|
||||
apiUrl: "https://api.yourdomain.com",
|
||||
environment: "production",
|
||||
});
|
||||
|
||||
async function createUser() {
|
||||
try {
|
||||
const result = await sdk.auth.register({
|
||||
username: "user@example.com",
|
||||
displayName: "John Doe",
|
||||
});
|
||||
|
||||
console.log("User created:", result);
|
||||
} catch (error) {
|
||||
console.error("Failed to create user:", error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **TypeScript**: ^5.3.0
|
||||
- **Axios**: ^1.6.0 (HTTP client)
|
||||
- **Zod**: ^3.22.0 (Schema validation)
|
||||
- **@simplewebauthn/browser**: ^9.0.0 (WebAuthn client)
|
||||
|
||||
## Contributing
|
||||
|
||||
When contributing to the SDK:
|
||||
|
||||
1. Follow TypeScript best practices
|
||||
2. Add comprehensive type definitions
|
||||
3. Include unit tests for new features
|
||||
4. Update documentation and examples
|
||||
5. Ensure backward compatibility
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "@sonr.io/sdk",
|
||||
"version": "0.0.11",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"type": "module",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc && tsc-alias",
|
||||
"dev": "concurrently \"tsc -w\" \"tsc-alias -w\"",
|
||||
"clean": "rm -rf dist",
|
||||
"test": "echo 'No tests defined for @sonr.io/sdk'",
|
||||
"lint": "biome check .",
|
||||
"format": "biome format . --write",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"prepublishOnly": "pnpm build",
|
||||
"release": "cz --no-raise 6,21 bump --yes --increment PATCH"
|
||||
},
|
||||
"dependencies": {
|
||||
"@simplewebauthn/browser": "^10.0.0",
|
||||
"@simplewebauthn/types": "^10.0.0",
|
||||
"@sonr.io/es": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.12.2",
|
||||
"concurrently": "^8.0.1",
|
||||
"rimraf": "^5.0.0",
|
||||
"tsc-alias": "^1.8.6",
|
||||
"typescript": "^5.3.3",
|
||||
"vitest": "^1.3.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export class HighwaySDK {
|
||||
private apiUrl: string;
|
||||
|
||||
constructor(config: { apiUrl?: string } = {}) {
|
||||
this.apiUrl = config.apiUrl || 'https://api.highway.sonr.io';
|
||||
}
|
||||
|
||||
async health(): Promise<any> {
|
||||
const response = await fetch(`${this.apiUrl}/health`);
|
||||
return response.json();
|
||||
}
|
||||
}
|
||||
|
||||
export default HighwaySDK;
|
||||
|
||||
// Export WebAuthn module
|
||||
export * from './webauthn';
|
||||
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* WebAuthn client for Sonr SDK
|
||||
*/
|
||||
|
||||
import {
|
||||
startAuthentication,
|
||||
startRegistration,
|
||||
} from '@simplewebauthn/browser';
|
||||
import type {
|
||||
PublicKeyCredentialCreationOptionsJSON,
|
||||
PublicKeyCredentialRequestOptionsJSON,
|
||||
RegistrationResponseJSON,
|
||||
AuthenticationResponseJSON,
|
||||
} from '@simplewebauthn/types';
|
||||
|
||||
import type {
|
||||
WebAuthnRegistrationOptions,
|
||||
WebAuthnAuthenticationOptions,
|
||||
WebAuthnRegistrationResult,
|
||||
WebAuthnAuthenticationResult,
|
||||
RegisterStartRequest,
|
||||
RegisterStartResponse,
|
||||
DIDDocument,
|
||||
DIDDocumentMetadata,
|
||||
} from './types';
|
||||
|
||||
export class WebAuthnClient {
|
||||
private apiUrl: string;
|
||||
private origin: string;
|
||||
|
||||
constructor(apiUrl: string, origin?: string) {
|
||||
this.apiUrl = apiUrl;
|
||||
this.origin = origin || 'http://localhost:3000';
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new user with WebAuthn
|
||||
*/
|
||||
async register(options: WebAuthnRegistrationOptions): Promise<WebAuthnRegistrationResult> {
|
||||
try {
|
||||
// Step 1: Call RegisterStart query to get WebAuthn options
|
||||
const startRequest: RegisterStartRequest = {
|
||||
assertion_value: options.email || options.tel || options.username,
|
||||
assertion_type: options.email ? 'email' : options.tel ? 'tel' : 'username',
|
||||
service_origin: options.origin || this.origin,
|
||||
};
|
||||
|
||||
const startResponse = await this.callRegisterStart(startRequest);
|
||||
|
||||
// Step 2: Create WebAuthn credential creation options
|
||||
const creationOptions: PublicKeyCredentialCreationOptionsJSON = {
|
||||
challenge: startResponse.challenge,
|
||||
rp: startResponse.rp,
|
||||
user: {
|
||||
id: startResponse.user.id,
|
||||
name: options.username,
|
||||
displayName: options.displayName || options.username,
|
||||
},
|
||||
pubKeyCredParams: (startResponse.pubKeyCredParams as PublicKeyCredentialCreationOptionsJSON['pubKeyCredParams']) || [
|
||||
{ type: 'public-key' as const, alg: -7 }, // ES256
|
||||
{ type: 'public-key' as const, alg: -257 }, // RS256
|
||||
],
|
||||
timeout: startResponse.timeout || 60000,
|
||||
attestation: startResponse.attestation || 'direct',
|
||||
authenticatorSelection: startResponse.authenticatorSelection || {
|
||||
authenticatorAttachment: 'platform',
|
||||
requireResidentKey: false,
|
||||
residentKey: 'preferred',
|
||||
userVerification: 'preferred',
|
||||
},
|
||||
};
|
||||
|
||||
// Step 3: Start WebAuthn registration ceremony
|
||||
const credential = await startRegistration(creationOptions);
|
||||
|
||||
// Step 4: Submit registration to blockchain
|
||||
const result = await this.submitRegistration({
|
||||
...options,
|
||||
credential,
|
||||
challenge: startResponse.challenge,
|
||||
});
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('WebAuthn registration error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Registration failed',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user with WebAuthn
|
||||
*/
|
||||
async authenticate(options: WebAuthnAuthenticationOptions): Promise<WebAuthnAuthenticationResult> {
|
||||
try {
|
||||
// Step 1: Get authentication options from the server
|
||||
const authOptions = await this.getAuthenticationOptions(options.username);
|
||||
|
||||
// Step 2: Create WebAuthn authentication options
|
||||
const requestOptions: PublicKeyCredentialRequestOptionsJSON = {
|
||||
challenge: authOptions.challenge,
|
||||
rpId: authOptions.rpId,
|
||||
timeout: authOptions.timeout || 60000,
|
||||
userVerification: authOptions.userVerification || 'preferred',
|
||||
allowCredentials: authOptions.allowCredentials,
|
||||
};
|
||||
|
||||
// Step 3: Start WebAuthn authentication ceremony
|
||||
const credential = await startAuthentication(requestOptions);
|
||||
|
||||
// Step 4: Verify authentication with the server
|
||||
const result = await this.verifyAuthentication({
|
||||
username: options.username,
|
||||
credential,
|
||||
challenge: authOptions.challenge,
|
||||
});
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('WebAuthn authentication error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Authentication failed',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call RegisterStart query
|
||||
*/
|
||||
private async callRegisterStart(request: RegisterStartRequest): Promise<RegisterStartResponse> {
|
||||
const response = await fetch(`${this.apiUrl}/did/v1/register/start`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(request),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ error: 'RegisterStart failed' })) as { error: string };
|
||||
throw new Error(error.error || 'RegisterStart failed');
|
||||
}
|
||||
|
||||
const data = await response.json() as any;
|
||||
|
||||
// Transform the response to match WebAuthn options format
|
||||
return {
|
||||
challenge: data.challenge || this.generateChallenge(),
|
||||
rp: {
|
||||
id: data.rp?.id || new URL(this.origin).hostname,
|
||||
name: data.rp?.name || 'Sonr Network',
|
||||
},
|
||||
user: {
|
||||
id: data.user?.id || this.generateUserId(),
|
||||
name: data.user?.name || request.assertion_value,
|
||||
displayName: data.user?.displayName || request.assertion_value,
|
||||
},
|
||||
pubKeyCredParams: data.pubKeyCredParams || [
|
||||
{ type: 'public-key' as const, alg: -7 }, // ES256
|
||||
{ type: 'public-key' as const, alg: -257 }, // RS256
|
||||
],
|
||||
timeout: data.timeout,
|
||||
attestation: data.attestation,
|
||||
authenticatorSelection: data.authenticatorSelection,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit registration to blockchain
|
||||
*/
|
||||
private async submitRegistration(data: {
|
||||
username: string;
|
||||
email?: string;
|
||||
tel?: string;
|
||||
createVault?: boolean;
|
||||
credential: RegistrationResponseJSON;
|
||||
challenge: string;
|
||||
}): Promise<WebAuthnRegistrationResult> {
|
||||
const response = await fetch(`${this.apiUrl}/did/v1/tx/register-webauthn-credential`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: data.username,
|
||||
assertion_value: data.email || data.tel || data.username,
|
||||
assertion_type: data.email ? 'email' : data.tel ? 'tel' : 'username',
|
||||
webauthn_credential: {
|
||||
credential_id: data.credential.id,
|
||||
public_key: data.credential.response.publicKey,
|
||||
attestation_object: data.credential.response.attestationObject,
|
||||
client_data_json: data.credential.response.clientDataJSON,
|
||||
authenticator_attachment: data.credential.authenticatorAttachment,
|
||||
},
|
||||
create_vault: data.createVault ?? true,
|
||||
challenge: data.challenge,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ error: 'Registration submission failed' })) as { error: string };
|
||||
throw new Error(error.error || 'Registration submission failed');
|
||||
}
|
||||
|
||||
const result = await response.json() as any;
|
||||
return {
|
||||
success: true,
|
||||
did: result.did,
|
||||
vaultId: result.vault_id,
|
||||
credential: result.credential,
|
||||
ucanToken: result.ucan_token,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication options
|
||||
*/
|
||||
private async getAuthenticationOptions(username: string): Promise<any> {
|
||||
const response = await fetch(`${this.apiUrl}/did/v1/login/start`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ username }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ error: 'Failed to get authentication options' })) as { error: string };
|
||||
throw new Error(error.error || 'Failed to get authentication options');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify authentication
|
||||
*/
|
||||
private async verifyAuthentication(data: {
|
||||
username: string;
|
||||
credential: AuthenticationResponseJSON;
|
||||
challenge: string;
|
||||
}): Promise<WebAuthnAuthenticationResult> {
|
||||
const response = await fetch(`${this.apiUrl}/did/v1/login/finish`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: data.username,
|
||||
credential: data.credential,
|
||||
challenge: data.challenge,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ error: 'Authentication verification failed' })) as { error: string };
|
||||
throw new Error(error.error || 'Authentication verification failed');
|
||||
}
|
||||
|
||||
const result = await response.json() as any;
|
||||
return {
|
||||
success: true,
|
||||
did: result.did,
|
||||
vaultId: result.vault_id,
|
||||
sessionToken: result.session_token,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DID document
|
||||
*/
|
||||
async getDIDDocument(did: string): Promise<{ document: DIDDocument; metadata: DIDDocumentMetadata }> {
|
||||
const response = await fetch(`${this.apiUrl}/did/v1/document/${did}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ error: 'Failed to get DID document' })) as { error: string };
|
||||
throw new Error(error.error || 'Failed to get DID document');
|
||||
}
|
||||
|
||||
const data = await response.json() as { did_document: DIDDocument; did_document_metadata: DIDDocumentMetadata };
|
||||
return {
|
||||
document: data.did_document,
|
||||
metadata: data.did_document_metadata,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random challenge
|
||||
*/
|
||||
private generateChallenge(): string {
|
||||
const array = new Uint8Array(32);
|
||||
crypto.getRandomValues(array);
|
||||
return btoa(String.fromCharCode(...array))
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random user ID
|
||||
*/
|
||||
private generateUserId(): string {
|
||||
const array = new Uint8Array(16);
|
||||
crypto.getRandomValues(array);
|
||||
return btoa(String.fromCharCode(...array))
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=/g, '');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* WebAuthn module exports
|
||||
*/
|
||||
|
||||
export { WebAuthnClient } from './client';
|
||||
export * from './types';
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* WebAuthn types for Sonr SDK
|
||||
*/
|
||||
|
||||
export interface WebAuthnRegistrationOptions {
|
||||
username: string;
|
||||
displayName?: string;
|
||||
email?: string;
|
||||
tel?: string;
|
||||
createVault?: boolean;
|
||||
origin?: string;
|
||||
}
|
||||
|
||||
export interface WebAuthnAuthenticationOptions {
|
||||
username: string;
|
||||
origin?: string;
|
||||
}
|
||||
|
||||
export interface WebAuthnCredential {
|
||||
id: string;
|
||||
rawId: string;
|
||||
type: string;
|
||||
publicKey: string;
|
||||
counter: number;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface RegisterStartRequest {
|
||||
assertion_value: string;
|
||||
assertion_type: 'email' | 'tel' | 'username';
|
||||
service_origin: string;
|
||||
}
|
||||
|
||||
export interface RegisterStartResponse {
|
||||
challenge: string;
|
||||
rp: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
user: {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
};
|
||||
pubKeyCredParams: Array<{
|
||||
type: string;
|
||||
alg: number;
|
||||
}>;
|
||||
timeout?: number;
|
||||
attestation?: AttestationConveyancePreference;
|
||||
authenticatorSelection?: AuthenticatorSelectionCriteria;
|
||||
}
|
||||
|
||||
export interface AuthenticatorSelectionCriteria {
|
||||
authenticatorAttachment?: AuthenticatorAttachment;
|
||||
requireResidentKey?: boolean;
|
||||
residentKey?: ResidentKeyRequirement;
|
||||
userVerification?: UserVerificationRequirement;
|
||||
}
|
||||
|
||||
export type AuthenticatorAttachment = 'platform' | 'cross-platform';
|
||||
export type ResidentKeyRequirement = 'discouraged' | 'preferred' | 'required';
|
||||
export type UserVerificationRequirement = 'required' | 'preferred' | 'discouraged';
|
||||
export type AttestationConveyancePreference = 'none' | 'indirect' | 'direct' | 'enterprise';
|
||||
|
||||
export interface WebAuthnRegistrationResult {
|
||||
success: boolean;
|
||||
did?: string;
|
||||
vaultId?: string;
|
||||
credential?: WebAuthnCredential;
|
||||
ucanToken?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface WebAuthnAuthenticationResult {
|
||||
success: boolean;
|
||||
did?: string;
|
||||
vaultId?: string;
|
||||
sessionToken?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface DIDDocument {
|
||||
id: string;
|
||||
controller: string[];
|
||||
verificationMethod?: VerificationMethod[];
|
||||
authentication?: Array<string | VerificationMethod>;
|
||||
assertionMethod?: Array<string | VerificationMethod>;
|
||||
keyAgreement?: Array<string | VerificationMethod>;
|
||||
capabilityInvocation?: Array<string | VerificationMethod>;
|
||||
capabilityDelegation?: Array<string | VerificationMethod>;
|
||||
service?: ServiceEndpoint[];
|
||||
}
|
||||
|
||||
export interface VerificationMethod {
|
||||
id: string;
|
||||
type: string;
|
||||
controller: string;
|
||||
publicKeyBase58?: string;
|
||||
publicKeyBase64?: string;
|
||||
publicKeyJwk?: any; // JsonWebKey interface from Web Crypto API
|
||||
publicKeyMultibase?: string;
|
||||
}
|
||||
|
||||
export interface ServiceEndpoint {
|
||||
id: string;
|
||||
type: string | string[];
|
||||
serviceEndpoint: string | string[] | Record<string, any>;
|
||||
}
|
||||
|
||||
export interface DIDDocumentMetadata {
|
||||
created?: string;
|
||||
updated?: string;
|
||||
deactivated?: boolean;
|
||||
versionId?: string;
|
||||
nextUpdate?: string;
|
||||
nextVersionId?: string;
|
||||
equivalentId?: string[];
|
||||
canonicalId?: string;
|
||||
ucanDelegationChain?: string;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2022"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowJs": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": false,
|
||||
"composite": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist", "test"]
|
||||
}
|
||||
Reference in New Issue
Block a user