mirror of
https://github.com/logos-messaging/OpChan.git
synced 2026-01-07 07:13:11 +00:00
chore: simplify DelegationManager
This commit is contained in:
parent
4232878d39
commit
5e0622183e
@ -3,7 +3,7 @@ import { useToast } from '@/components/ui/use-toast';
|
|||||||
import { OpchanMessage } from '@/types/forum';
|
import { OpchanMessage } from '@/types/forum';
|
||||||
import { User, EVerificationStatus, DisplayPreference } from '@/types/identity';
|
import { User, EVerificationStatus, DisplayPreference } from '@/types/identity';
|
||||||
import { WalletManager } from '@/lib/wallet';
|
import { WalletManager } from '@/lib/wallet';
|
||||||
import { DelegationManager, DelegationDuration } from '@/lib/delegation';
|
import { DelegationManager, DelegationDuration, DelegationFullStatus } from '@/lib/delegation';
|
||||||
import { useAppKitAccount, useDisconnect, modal } from '@reown/appkit/react';
|
import { useAppKitAccount, useDisconnect, modal } from '@reown/appkit/react';
|
||||||
|
|
||||||
export type VerificationStatus =
|
export type VerificationStatus =
|
||||||
@ -22,8 +22,7 @@ interface AuthContextType {
|
|||||||
disconnectWallet: () => void;
|
disconnectWallet: () => void;
|
||||||
verifyOwnership: () => Promise<boolean>;
|
verifyOwnership: () => Promise<boolean>;
|
||||||
delegateKey: (duration?: DelegationDuration) => Promise<boolean>;
|
delegateKey: (duration?: DelegationDuration) => Promise<boolean>;
|
||||||
isDelegationValid: () => boolean;
|
getDelegationStatus: () => DelegationFullStatus;
|
||||||
delegationTimeRemaining: () => number;
|
|
||||||
clearDelegation: () => void;
|
clearDelegation: () => void;
|
||||||
signMessage: (message: OpchanMessage) => Promise<OpchanMessage | null>;
|
signMessage: (message: OpchanMessage) => Promise<OpchanMessage | null>;
|
||||||
verifyMessage: (message: OpchanMessage) => boolean;
|
verifyMessage: (message: OpchanMessage) => boolean;
|
||||||
@ -166,32 +165,13 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate new keypair
|
// Use the simplified delegation method
|
||||||
const keypair = delegationManager.generateKeypair();
|
return await delegationManager.delegate(
|
||||||
|
|
||||||
// Create delegation message with expiry
|
|
||||||
const expiryHours = DelegationManager.getDurationHours(duration);
|
|
||||||
const expiryTimestamp = Date.now() + expiryHours * 60 * 60 * 1000;
|
|
||||||
const delegationMessage = delegationManager.createDelegationMessage(
|
|
||||||
keypair.publicKey,
|
|
||||||
user.address,
|
user.address,
|
||||||
expiryTimestamp
|
user.walletType,
|
||||||
);
|
|
||||||
|
|
||||||
// Sign the delegation message with wallet
|
|
||||||
const signature = await walletManager.signMessage(delegationMessage);
|
|
||||||
|
|
||||||
// Create and store the delegation
|
|
||||||
delegationManager.createDelegation(
|
|
||||||
user.address,
|
|
||||||
signature,
|
|
||||||
keypair.publicKey,
|
|
||||||
keypair.privateKey,
|
|
||||||
duration,
|
duration,
|
||||||
user.walletType
|
(message) => walletManager.signMessage(message)
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
`Error creating key delegation for ${user.walletType}:`,
|
`Error creating key delegation for ${user.walletType}:`,
|
||||||
@ -419,15 +399,14 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update user with delegation info
|
// Update user with delegation info
|
||||||
const browserPublicKey = delegationManager.getBrowserPublicKey();
|
const delegationStatus = delegationManager.getStatus(
|
||||||
const delegationStatus = delegationManager.getDelegationStatus(
|
|
||||||
currentUser.address,
|
currentUser.address,
|
||||||
currentUser.walletType
|
currentUser.walletType
|
||||||
);
|
);
|
||||||
|
|
||||||
const updatedUser = {
|
const updatedUser = {
|
||||||
...currentUser,
|
...currentUser,
|
||||||
browserPubKey: browserPublicKey || undefined,
|
browserPubKey: delegationStatus.publicKey || undefined,
|
||||||
delegationSignature: delegationStatus.isValid ? 'valid' : undefined,
|
delegationSignature: delegationStatus.isValid ? 'valid' : undefined,
|
||||||
delegationExpiry: delegationStatus.timeRemaining
|
delegationExpiry: delegationStatus.timeRemaining
|
||||||
? Date.now() + delegationStatus.timeRemaining
|
? Date.now() + delegationStatus.timeRemaining
|
||||||
@ -467,16 +446,12 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isDelegationValid = (): boolean => {
|
const getDelegationStatus = (): DelegationFullStatus => {
|
||||||
return delegationManager.isDelegationValid();
|
return delegationManager.getStatus(currentUser?.address, currentUser?.walletType);
|
||||||
};
|
|
||||||
|
|
||||||
const delegationTimeRemaining = (): number => {
|
|
||||||
return delegationManager.getDelegationTimeRemaining();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearDelegation = (): void => {
|
const clearDelegation = (): void => {
|
||||||
delegationManager.clearDelegation();
|
delegationManager.clear();
|
||||||
|
|
||||||
// Update the current user to remove delegation info
|
// Update the current user to remove delegation info
|
||||||
if (currentUser) {
|
if (currentUser) {
|
||||||
@ -500,10 +475,10 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
signMessage: async (
|
signMessage: async (
|
||||||
message: OpchanMessage
|
message: OpchanMessage
|
||||||
): Promise<OpchanMessage | null> => {
|
): Promise<OpchanMessage | null> => {
|
||||||
return delegationManager.signMessageWithDelegatedKey(message);
|
return delegationManager.signMessage(message);
|
||||||
},
|
},
|
||||||
verifyMessage: (message: OpchanMessage): boolean => {
|
verifyMessage: (message: OpchanMessage): boolean => {
|
||||||
return delegationManager.verifyMessage(message);
|
return delegationManager.verify(message);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -516,8 +491,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
disconnectWallet,
|
disconnectWallet,
|
||||||
verifyOwnership,
|
verifyOwnership,
|
||||||
delegateKey,
|
delegateKey,
|
||||||
isDelegationValid,
|
getDelegationStatus,
|
||||||
delegationTimeRemaining,
|
|
||||||
clearDelegation,
|
clearDelegation,
|
||||||
signMessage: messageSigning.signMessage,
|
signMessage: messageSigning.signMessage,
|
||||||
verifyMessage: messageSigning.verifyMessage,
|
verifyMessage: messageSigning.verifyMessage,
|
||||||
|
|||||||
@ -11,8 +11,7 @@ export const useDelegation = () => {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
delegateKey: contextDelegateKey,
|
delegateKey: contextDelegateKey,
|
||||||
isDelegationValid: contextIsDelegationValid,
|
getDelegationStatus: contextGetDelegationStatus,
|
||||||
delegationTimeRemaining: contextDelegationTimeRemaining,
|
|
||||||
clearDelegation: contextClearDelegation,
|
clearDelegation: contextClearDelegation,
|
||||||
isAuthenticating,
|
isAuthenticating,
|
||||||
} = context;
|
} = context;
|
||||||
@ -29,17 +28,19 @@ export const useDelegation = () => {
|
|||||||
}, [contextClearDelegation]);
|
}, [contextClearDelegation]);
|
||||||
|
|
||||||
const delegationStatus = useMemo(() => {
|
const delegationStatus = useMemo(() => {
|
||||||
const isValid = contextIsDelegationValid();
|
const status = contextGetDelegationStatus();
|
||||||
const timeRemaining = contextDelegationTimeRemaining();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasDelegation: timeRemaining > 0,
|
hasDelegation: status.hasDelegation,
|
||||||
isValid,
|
isValid: status.isValid,
|
||||||
timeRemaining: timeRemaining > 0 ? timeRemaining : undefined,
|
timeRemaining: status.timeRemaining,
|
||||||
expiresAt:
|
expiresAt:
|
||||||
timeRemaining > 0 ? new Date(Date.now() + timeRemaining) : undefined,
|
status.timeRemaining ? new Date(Date.now() + status.timeRemaining) : undefined,
|
||||||
|
publicKey: status.publicKey,
|
||||||
|
address: status.address,
|
||||||
|
walletType: status.walletType,
|
||||||
};
|
};
|
||||||
}, [contextIsDelegationValid, contextDelegationTimeRemaining]);
|
}, [contextGetDelegationStatus]);
|
||||||
|
|
||||||
const formatTimeRemaining = useCallback((timeMs: number): string => {
|
const formatTimeRemaining = useCallback((timeMs: number): string => {
|
||||||
const hours = Math.floor(timeMs / (1000 * 60 * 60));
|
const hours = Math.floor(timeMs / (1000 * 60 * 60));
|
||||||
|
|||||||
@ -9,6 +9,13 @@ import { DelegationStorage } from './storage';
|
|||||||
// Set up ed25519 with sha512
|
// Set up ed25519 with sha512
|
||||||
ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));
|
ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));
|
||||||
|
|
||||||
|
// Enhanced status interface that consolidates all delegation information
|
||||||
|
export interface DelegationFullStatus extends DelegationStatus {
|
||||||
|
publicKey?: string;
|
||||||
|
address?: string;
|
||||||
|
walletType?: 'bitcoin' | 'ethereum';
|
||||||
|
}
|
||||||
|
|
||||||
export class DelegationManager {
|
export class DelegationManager {
|
||||||
// Duration options in hours
|
// Duration options in hours
|
||||||
private static readonly DURATION_HOURS = {
|
private static readonly DURATION_HOURS = {
|
||||||
@ -24,166 +31,112 @@ export class DelegationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// KEYPAIR GENERATION
|
// PUBLIC API
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a new browser-based keypair for signing messages
|
* Create a complete delegation with a single method call
|
||||||
|
* @param address - Wallet address to delegate from
|
||||||
|
* @param walletType - Type of wallet (bitcoin/ethereum)
|
||||||
|
* @param duration - How long the delegation should last
|
||||||
|
* @param signFunction - Function to sign the delegation message with the wallet
|
||||||
|
* @returns Promise<boolean> - Success status
|
||||||
*/
|
*/
|
||||||
generateKeypair(): { publicKey: string; privateKey: string } {
|
async delegate(
|
||||||
const privateKey = ed.utils.randomPrivateKey();
|
address: string,
|
||||||
const privateKeyHex = bytesToHex(privateKey);
|
walletType: 'bitcoin' | 'ethereum',
|
||||||
|
|
||||||
const publicKey = ed.getPublicKey(privateKey);
|
|
||||||
const publicKeyHex = bytesToHex(publicKey);
|
|
||||||
|
|
||||||
return {
|
|
||||||
privateKey: privateKeyHex,
|
|
||||||
publicKey: publicKeyHex,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a delegation message to be signed by the wallet
|
|
||||||
*/
|
|
||||||
createDelegationMessage(
|
|
||||||
browserPublicKey: string,
|
|
||||||
walletAddress: string,
|
|
||||||
expiryTimestamp: number
|
|
||||||
): string {
|
|
||||||
return `I, ${walletAddress}, delegate authority to this pubkey: ${browserPublicKey} until ${expiryTimestamp}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// DELEGATION LIFECYCLE
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create and store a delegation
|
|
||||||
*/
|
|
||||||
createDelegation(
|
|
||||||
walletAddress: string,
|
|
||||||
signature: string,
|
|
||||||
browserPublicKey: string,
|
|
||||||
browserPrivateKey: string,
|
|
||||||
duration: DelegationDuration = '7days',
|
duration: DelegationDuration = '7days',
|
||||||
walletType: 'bitcoin' | 'ethereum'
|
signFunction: (message: string) => Promise<string>
|
||||||
): void {
|
): Promise<boolean> {
|
||||||
const expiryHours = DelegationManager.getDurationHours(duration);
|
try {
|
||||||
const expiryTimestamp = Date.now() + expiryHours * 60 * 60 * 1000;
|
// Generate new keypair
|
||||||
|
const keypair = this.generateKeypair();
|
||||||
|
|
||||||
|
// Create delegation message with expiry
|
||||||
|
const expiryHours = DelegationManager.getDurationHours(duration);
|
||||||
|
const expiryTimestamp = Date.now() + expiryHours * 60 * 60 * 1000;
|
||||||
|
const delegationMessage = this.createDelegationMessage(
|
||||||
|
keypair.publicKey,
|
||||||
|
address,
|
||||||
|
expiryTimestamp
|
||||||
|
);
|
||||||
|
|
||||||
const delegationInfo: DelegationInfo = {
|
// Sign the delegation message with wallet
|
||||||
signature,
|
const signature = await signFunction(delegationMessage);
|
||||||
expiryTimestamp,
|
|
||||||
browserPublicKey,
|
|
||||||
browserPrivateKey,
|
|
||||||
walletAddress,
|
|
||||||
walletType,
|
|
||||||
};
|
|
||||||
|
|
||||||
DelegationStorage.store(delegationInfo);
|
// Create and store the delegation
|
||||||
|
const delegationInfo: DelegationInfo = {
|
||||||
|
signature,
|
||||||
|
expiryTimestamp,
|
||||||
|
browserPublicKey: keypair.publicKey,
|
||||||
|
browserPrivateKey: keypair.privateKey,
|
||||||
|
walletAddress: address,
|
||||||
|
walletType,
|
||||||
|
};
|
||||||
|
|
||||||
|
DelegationStorage.store(delegationInfo);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating delegation:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a delegation is valid
|
* Get comprehensive delegation status
|
||||||
|
* @param currentAddress - Optional address to validate against
|
||||||
|
* @param currentWalletType - Optional wallet type to validate against
|
||||||
|
* @returns Complete delegation status information
|
||||||
*/
|
*/
|
||||||
isDelegationValid(
|
getStatus(
|
||||||
currentAddress?: string,
|
currentAddress?: string,
|
||||||
currentWalletType?: 'bitcoin' | 'ethereum'
|
currentWalletType?: 'bitcoin' | 'ethereum'
|
||||||
): boolean {
|
): DelegationFullStatus {
|
||||||
const delegation = DelegationStorage.retrieve();
|
const delegation = DelegationStorage.retrieve();
|
||||||
if (!delegation) return false;
|
|
||||||
|
if (!delegation) {
|
||||||
|
return {
|
||||||
|
hasDelegation: false,
|
||||||
|
isValid: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Check if delegation has expired
|
// Check if delegation has expired
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
if (now >= delegation.expiryTimestamp) return false;
|
const hasExpired = now >= delegation.expiryTimestamp;
|
||||||
|
|
||||||
// If a current address is provided, validate it matches the delegation
|
// Check address/wallet type matching if provided
|
||||||
if (currentAddress && delegation.walletAddress !== currentAddress) {
|
const addressMatches = !currentAddress || delegation.walletAddress === currentAddress;
|
||||||
return false;
|
const walletTypeMatches = !currentWalletType || delegation.walletType === currentWalletType;
|
||||||
}
|
|
||||||
|
const isValid = !hasExpired && addressMatches && walletTypeMatches;
|
||||||
// If a current wallet type is provided, validate it matches the delegation
|
const timeRemaining = Math.max(0, delegation.expiryTimestamp - now);
|
||||||
if (currentWalletType && delegation.walletType !== currentWalletType) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the time remaining on the current delegation in milliseconds
|
|
||||||
*/
|
|
||||||
getDelegationTimeRemaining(): number {
|
|
||||||
const delegation = DelegationStorage.retrieve();
|
|
||||||
if (!delegation) return 0;
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
return Math.max(0, delegation.expiryTimestamp - now);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the browser public key from the current delegation
|
|
||||||
*/
|
|
||||||
getBrowserPublicKey(): string | null {
|
|
||||||
const delegation = DelegationStorage.retrieve();
|
|
||||||
if (!delegation) return null;
|
|
||||||
return delegation.browserPublicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get delegation status
|
|
||||||
*/
|
|
||||||
getDelegationStatus(
|
|
||||||
currentAddress?: string,
|
|
||||||
currentWalletType?: 'bitcoin' | 'ethereum'
|
|
||||||
): DelegationStatus {
|
|
||||||
const hasDelegation = this.getBrowserPublicKey() !== null;
|
|
||||||
const isValid = this.isDelegationValid(currentAddress, currentWalletType);
|
|
||||||
const timeRemaining = this.getDelegationTimeRemaining();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasDelegation,
|
hasDelegation: true,
|
||||||
isValid,
|
isValid,
|
||||||
timeRemaining: timeRemaining > 0 ? timeRemaining : undefined,
|
timeRemaining: timeRemaining > 0 ? timeRemaining : undefined,
|
||||||
|
publicKey: delegation.browserPublicKey,
|
||||||
|
address: delegation.walletAddress,
|
||||||
|
walletType: delegation.walletType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the stored delegation
|
* Clear the stored delegation
|
||||||
*/
|
*/
|
||||||
clearDelegation(): void {
|
clear(): void {
|
||||||
DelegationStorage.clear();
|
DelegationStorage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// MESSAGE SIGNING & VERIFICATION
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign a raw string message using the browser-generated private key
|
* Sign a message with the delegated browser key
|
||||||
|
* @param message - Unsigned message to sign
|
||||||
|
* @returns Signed message or null if delegation invalid
|
||||||
*/
|
*/
|
||||||
signRawMessage(message: string): string | null {
|
signMessage(message: UnsignedMessage): OpchanMessage | null {
|
||||||
const delegation = DelegationStorage.retrieve();
|
const status = this.getStatus();
|
||||||
if (!delegation || !this.isDelegationValid()) return null;
|
if (!status.isValid) {
|
||||||
|
|
||||||
try {
|
|
||||||
const privateKeyBytes = hexToBytes(delegation.browserPrivateKey);
|
|
||||||
const messageBytes = new TextEncoder().encode(message);
|
|
||||||
|
|
||||||
const signature = ed.sign(messageBytes, privateKeyBytes);
|
|
||||||
return bytesToHex(signature);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error signing with browser key:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sign an unsigned message with the delegated browser key
|
|
||||||
*/
|
|
||||||
signMessageWithDelegatedKey(message: UnsignedMessage): OpchanMessage | null {
|
|
||||||
if (!this.isDelegationValid()) {
|
|
||||||
console.error('No valid key delegation found. Cannot sign message.');
|
console.error('No valid key delegation found. Cannot sign message.');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -198,7 +151,7 @@ export class DelegationManager {
|
|||||||
browserPubKey: undefined,
|
browserPubKey: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const signature = this.signRawMessage(messageToSign);
|
const signature = this.signRaw(messageToSign);
|
||||||
if (!signature) return null;
|
if (!signature) return null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -209,9 +162,11 @@ export class DelegationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify an OpchanMessage signature
|
* Verify a message signature
|
||||||
|
* @param message - Signed message to verify
|
||||||
|
* @returns True if signature is valid
|
||||||
*/
|
*/
|
||||||
verifyMessage(message: OpchanMessage): boolean {
|
verify(message: OpchanMessage): boolean {
|
||||||
// Check for required signature fields
|
// Check for required signature fields
|
||||||
if (!message.signature || !message.browserPubKey) {
|
if (!message.signature || !message.browserPubKey) {
|
||||||
const messageId = message.id || `${message.type}-${message.timestamp}`;
|
const messageId = message.id || `${message.type}-${message.timestamp}`;
|
||||||
@ -227,7 +182,7 @@ export class DelegationManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Verify the signature
|
// Verify the signature
|
||||||
const isValid = this.verifyRawSignature(
|
const isValid = this.verifyRaw(
|
||||||
signedContent,
|
signedContent,
|
||||||
message.signature,
|
message.signature,
|
||||||
message.browserPubKey
|
message.browserPubKey
|
||||||
@ -241,10 +196,60 @@ export class DelegationManager {
|
|||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// PRIVATE HELPERS
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a new browser-based keypair for signing messages
|
||||||
|
*/
|
||||||
|
private generateKeypair(): { publicKey: string; privateKey: string } {
|
||||||
|
const privateKey = ed.utils.randomPrivateKey();
|
||||||
|
const privateKeyHex = bytesToHex(privateKey);
|
||||||
|
|
||||||
|
const publicKey = ed.getPublicKey(privateKey);
|
||||||
|
const publicKeyHex = bytesToHex(publicKey);
|
||||||
|
|
||||||
|
return {
|
||||||
|
privateKey: privateKeyHex,
|
||||||
|
publicKey: publicKeyHex,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a delegation message to be signed by the wallet
|
||||||
|
*/
|
||||||
|
private createDelegationMessage(
|
||||||
|
browserPublicKey: string,
|
||||||
|
walletAddress: string,
|
||||||
|
expiryTimestamp: number
|
||||||
|
): string {
|
||||||
|
return `I, ${walletAddress}, delegate authority to this pubkey: ${browserPublicKey} until ${expiryTimestamp}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a raw string message using the browser-generated private key
|
||||||
|
*/
|
||||||
|
private signRaw(message: string): string | null {
|
||||||
|
const delegation = DelegationStorage.retrieve();
|
||||||
|
if (!delegation) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const privateKeyBytes = hexToBytes(delegation.browserPrivateKey);
|
||||||
|
const messageBytes = new TextEncoder().encode(message);
|
||||||
|
|
||||||
|
const signature = ed.sign(messageBytes, privateKeyBytes);
|
||||||
|
return bytesToHex(signature);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error signing with browser key:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify a signature made with the browser key
|
* Verify a signature made with the browser key
|
||||||
*/
|
*/
|
||||||
private verifyRawSignature(
|
private verifyRaw(
|
||||||
message: string,
|
message: string,
|
||||||
signature: string,
|
signature: string,
|
||||||
publicKey: string
|
publicKey: string
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user