@xtr-dev/rondevu-client 0.7.12 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +459 -404
- package/dist/discovery.d.ts +93 -0
- package/dist/discovery.js +164 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +6 -2
- package/dist/offer-pool.d.ts +74 -0
- package/dist/offer-pool.js +119 -0
- package/dist/rondevu.d.ts +16 -1
- package/dist/rondevu.js +29 -2
- package/dist/service-pool.d.ts +115 -0
- package/dist/service-pool.js +339 -0
- package/dist/services.d.ts +79 -0
- package/dist/services.js +206 -0
- package/dist/usernames.d.ts +79 -0
- package/dist/usernames.js +147 -0
- package/package.json +3 -3
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import * as ed25519 from '@noble/ed25519';
|
|
2
|
+
/**
|
|
3
|
+
* Convert Uint8Array to base64 string
|
|
4
|
+
*/
|
|
5
|
+
function bytesToBase64(bytes) {
|
|
6
|
+
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join('');
|
|
7
|
+
return btoa(binString);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Convert base64 string to Uint8Array
|
|
11
|
+
*/
|
|
12
|
+
function base64ToBytes(base64) {
|
|
13
|
+
const binString = atob(base64);
|
|
14
|
+
return Uint8Array.from(binString, (char) => char.codePointAt(0));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Rondevu Username API
|
|
18
|
+
* Handles username claiming with Ed25519 cryptographic proof
|
|
19
|
+
*/
|
|
20
|
+
export class RondevuUsername {
|
|
21
|
+
constructor(baseUrl) {
|
|
22
|
+
this.baseUrl = baseUrl;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generates an Ed25519 keypair for username claiming
|
|
26
|
+
*/
|
|
27
|
+
async generateKeypair() {
|
|
28
|
+
const privateKey = ed25519.utils.randomSecretKey();
|
|
29
|
+
const publicKey = await ed25519.getPublicKey(privateKey);
|
|
30
|
+
return {
|
|
31
|
+
publicKey: bytesToBase64(publicKey),
|
|
32
|
+
privateKey: bytesToBase64(privateKey)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Signs a message with an Ed25519 private key
|
|
37
|
+
*/
|
|
38
|
+
async signMessage(message, privateKeyBase64) {
|
|
39
|
+
const privateKey = base64ToBytes(privateKeyBase64);
|
|
40
|
+
const encoder = new TextEncoder();
|
|
41
|
+
const messageBytes = encoder.encode(message);
|
|
42
|
+
const signature = await ed25519.sign(messageBytes, privateKey);
|
|
43
|
+
return bytesToBase64(signature);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Claims a username
|
|
47
|
+
* Generates a new keypair if one is not provided
|
|
48
|
+
*/
|
|
49
|
+
async claimUsername(username, existingKeypair) {
|
|
50
|
+
// Generate or use existing keypair
|
|
51
|
+
const keypair = existingKeypair || await this.generateKeypair();
|
|
52
|
+
// Create signed message
|
|
53
|
+
const timestamp = Date.now();
|
|
54
|
+
const message = `claim:${username}:${timestamp}`;
|
|
55
|
+
const signature = await this.signMessage(message, keypair.privateKey);
|
|
56
|
+
// Send claim request
|
|
57
|
+
const response = await fetch(`${this.baseUrl}/usernames/claim`, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: { 'Content-Type': 'application/json' },
|
|
60
|
+
body: JSON.stringify({
|
|
61
|
+
username,
|
|
62
|
+
publicKey: keypair.publicKey,
|
|
63
|
+
signature,
|
|
64
|
+
message
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
const error = await response.json();
|
|
69
|
+
throw new Error(error.error || 'Failed to claim username');
|
|
70
|
+
}
|
|
71
|
+
const data = await response.json();
|
|
72
|
+
return {
|
|
73
|
+
username: data.username,
|
|
74
|
+
publicKey: keypair.publicKey,
|
|
75
|
+
privateKey: keypair.privateKey,
|
|
76
|
+
claimedAt: data.claimedAt,
|
|
77
|
+
expiresAt: data.expiresAt
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Checks if a username is available
|
|
82
|
+
*/
|
|
83
|
+
async checkUsername(username) {
|
|
84
|
+
const response = await fetch(`${this.baseUrl}/usernames/${username}`);
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
throw new Error('Failed to check username');
|
|
87
|
+
}
|
|
88
|
+
const data = await response.json();
|
|
89
|
+
return {
|
|
90
|
+
username: data.username,
|
|
91
|
+
available: data.available,
|
|
92
|
+
claimedAt: data.claimedAt,
|
|
93
|
+
expiresAt: data.expiresAt,
|
|
94
|
+
publicKey: data.publicKey
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Helper: Save keypair to localStorage
|
|
99
|
+
* WARNING: This stores the private key in localStorage which is not the most secure
|
|
100
|
+
* For production use, consider using IndexedDB with encryption or hardware security modules
|
|
101
|
+
*/
|
|
102
|
+
saveKeypairToStorage(username, publicKey, privateKey) {
|
|
103
|
+
const data = { username, publicKey, privateKey, savedAt: Date.now() };
|
|
104
|
+
localStorage.setItem(`rondevu:keypair:${username}`, JSON.stringify(data));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Helper: Load keypair from localStorage
|
|
108
|
+
*/
|
|
109
|
+
loadKeypairFromStorage(username) {
|
|
110
|
+
const stored = localStorage.getItem(`rondevu:keypair:${username}`);
|
|
111
|
+
if (!stored)
|
|
112
|
+
return null;
|
|
113
|
+
try {
|
|
114
|
+
const data = JSON.parse(stored);
|
|
115
|
+
return { publicKey: data.publicKey, privateKey: data.privateKey };
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Helper: Delete keypair from localStorage
|
|
123
|
+
*/
|
|
124
|
+
deleteKeypairFromStorage(username) {
|
|
125
|
+
localStorage.removeItem(`rondevu:keypair:${username}`);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Export keypair as JSON string (for backup)
|
|
129
|
+
*/
|
|
130
|
+
exportKeypair(publicKey, privateKey) {
|
|
131
|
+
return JSON.stringify({
|
|
132
|
+
publicKey,
|
|
133
|
+
privateKey,
|
|
134
|
+
exportedAt: Date.now()
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Import keypair from JSON string
|
|
139
|
+
*/
|
|
140
|
+
importKeypair(json) {
|
|
141
|
+
const data = JSON.parse(json);
|
|
142
|
+
if (!data.publicKey || !data.privateKey) {
|
|
143
|
+
throw new Error('Invalid keypair format');
|
|
144
|
+
}
|
|
145
|
+
return { publicKey: data.publicKey, privateKey: data.privateKey };
|
|
146
|
+
}
|
|
147
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xtr-dev/rondevu-client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "TypeScript client for Rondevu
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "TypeScript client for Rondevu DNS-like WebRTC with username claiming and service discovery",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -27,6 +27,6 @@
|
|
|
27
27
|
"README.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@
|
|
30
|
+
"@noble/ed25519": "^3.0.0"
|
|
31
31
|
}
|
|
32
32
|
}
|