shogun-core 1.2.7 → 1.2.8
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 +0 -1
- package/dist/browser/shogun-core.js +1 -1
- package/dist/browser/shogun-core.js.LICENSE.txt +2 -0
- package/dist/browser/shogun-core.light.js +1 -1
- package/dist/browser/shogun-core.vendors.light.js +1 -1
- package/dist/core.js +31 -71
- package/dist/gundb/{instance.js → gunInstance.js} +135 -115
- package/dist/gundb/index.js +3 -20
- package/dist/plugins/index.js +23 -1
- package/dist/plugins/nostr/index.js +1 -0
- package/dist/plugins/nostr/nostrChain.js +128 -0
- package/dist/plugins/nostr/nostrConnector.js +42 -7
- package/dist/plugins/nostr/nostrConnectorPlugin.js +157 -1
- package/dist/plugins/nostr/nostrSigner.js +343 -0
- package/dist/plugins/oauth/index.js +13 -0
- package/dist/plugins/oauth/oauthChain.js +161 -0
- package/dist/plugins/oauth/oauthConnector.js +542 -0
- package/dist/plugins/oauth/oauthPlugin.js +302 -0
- package/dist/plugins/oauth/types.js +2 -0
- package/dist/plugins/web3/index.js +1 -0
- package/dist/plugins/web3/web3Chain.js +77 -2
- package/dist/plugins/web3/web3Connector.js +159 -37
- package/dist/plugins/web3/web3ConnectorPlugin.js +157 -1
- package/dist/plugins/web3/web3Signer.js +268 -0
- package/dist/plugins/webauthn/webauthnChain.js +78 -0
- package/dist/plugins/webauthn/webauthnPlugin.js +154 -1
- package/dist/plugins/webauthn/webauthnSigner.js +318 -0
- package/dist/storage/storage.js +0 -8
- package/dist/types/core.d.ts +10 -34
- package/dist/types/gundb/gun-es/gun-es.d.ts +1 -0
- package/dist/types/gundb/{instance.d.ts → gunInstance.d.ts} +2 -2
- package/dist/types/gundb/index.d.ts +1 -4
- package/dist/types/plugins/index.d.ts +4 -0
- package/dist/types/plugins/nostr/index.d.ts +1 -0
- package/dist/types/plugins/nostr/nostrConnector.d.ts +3 -2
- package/dist/types/plugins/nostr/nostrConnectorPlugin.d.ts +82 -0
- package/dist/types/plugins/nostr/nostrSigner.d.ts +104 -0
- package/dist/types/plugins/oauth/index.d.ts +4 -0
- package/dist/types/plugins/oauth/oauthChain.d.ts +2 -0
- package/dist/types/plugins/oauth/oauthConnector.d.ts +100 -0
- package/dist/types/plugins/oauth/oauthPlugin.d.ts +89 -0
- package/dist/types/plugins/oauth/types.d.ts +106 -0
- package/dist/types/plugins/web3/index.d.ts +1 -0
- package/dist/types/plugins/web3/types.d.ts +1 -0
- package/dist/types/plugins/web3/web3Connector.d.ts +8 -2
- package/dist/types/plugins/web3/web3ConnectorPlugin.d.ts +82 -0
- package/dist/types/plugins/web3/web3Signer.d.ts +93 -0
- package/dist/types/plugins/webauthn/webauthnPlugin.d.ts +81 -0
- package/dist/types/plugins/webauthn/webauthnSigner.d.ts +90 -0
- package/dist/types/shogun.js +1 -28
- package/dist/types/types/events.d.ts +2 -2
- package/dist/types/types/shogun.d.ts +13 -49
- package/package.json +2 -1
- package/dist/browser.js +0 -107
- package/dist/contracts/base.js +0 -152
- package/dist/contracts/entryPoint.js +0 -407
- package/dist/contracts/index.js +0 -47
- package/dist/contracts/registry.js +0 -259
- package/dist/contracts/relay.js +0 -494
- package/dist/contracts/utils.js +0 -582
- package/dist/types/browser.d.ts +0 -27
- package/dist/types/contracts/base.d.ts +0 -82
- package/dist/types/contracts/entryPoint.d.ts +0 -138
- package/dist/types/contracts/index.d.ts +0 -17
- package/dist/types/contracts/registry.d.ts +0 -97
- package/dist/types/contracts/relay.d.ts +0 -165
- package/dist/types/contracts/utils.d.ts +0 -173
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.WebauthnPlugin = void 0;
|
|
4
4
|
const base_1 = require("../base");
|
|
5
5
|
const webauthn_1 = require("./webauthn");
|
|
6
|
+
const webauthnSigner_1 = require("./webauthnSigner");
|
|
6
7
|
const logger_1 = require("../../utils/logger");
|
|
7
8
|
const ethers_1 = require("ethers");
|
|
8
9
|
const errorHandler_1 = require("../../utils/errorHandler");
|
|
@@ -14,6 +15,7 @@ class WebauthnPlugin extends base_1.BasePlugin {
|
|
|
14
15
|
version = "1.0.0";
|
|
15
16
|
description = "Provides WebAuthn authentication functionality for ShogunCore";
|
|
16
17
|
webauthn = null;
|
|
18
|
+
signer = null;
|
|
17
19
|
/**
|
|
18
20
|
* @inheritdoc
|
|
19
21
|
*/
|
|
@@ -21,13 +23,15 @@ class WebauthnPlugin extends base_1.BasePlugin {
|
|
|
21
23
|
super.initialize(core);
|
|
22
24
|
// Inizializziamo il modulo WebAuthn
|
|
23
25
|
this.webauthn = new webauthn_1.Webauthn(core.gun);
|
|
24
|
-
|
|
26
|
+
this.signer = new webauthnSigner_1.WebAuthnSigner(this.webauthn);
|
|
27
|
+
(0, logger_1.log)("WebAuthn plugin initialized with signer support");
|
|
25
28
|
}
|
|
26
29
|
/**
|
|
27
30
|
* @inheritdoc
|
|
28
31
|
*/
|
|
29
32
|
destroy() {
|
|
30
33
|
this.webauthn = null;
|
|
34
|
+
this.signer = null;
|
|
31
35
|
super.destroy();
|
|
32
36
|
(0, logger_1.log)("WebAuthn plugin destroyed");
|
|
33
37
|
}
|
|
@@ -42,6 +46,17 @@ class WebauthnPlugin extends base_1.BasePlugin {
|
|
|
42
46
|
}
|
|
43
47
|
return this.webauthn;
|
|
44
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Assicura che il signer sia inizializzato
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
assertSigner() {
|
|
54
|
+
this.assertInitialized();
|
|
55
|
+
if (!this.signer) {
|
|
56
|
+
throw new Error("WebAuthn signer not initialized");
|
|
57
|
+
}
|
|
58
|
+
return this.signer;
|
|
59
|
+
}
|
|
45
60
|
/**
|
|
46
61
|
* @inheritdoc
|
|
47
62
|
*/
|
|
@@ -78,6 +93,144 @@ class WebauthnPlugin extends base_1.BasePlugin {
|
|
|
78
93
|
async removeDevice(username, credentialId, credentials) {
|
|
79
94
|
return this.assertWebauthn().removeDevice(username, credentialId, credentials);
|
|
80
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* @inheritdoc
|
|
98
|
+
*/
|
|
99
|
+
async createSigningCredential(username) {
|
|
100
|
+
try {
|
|
101
|
+
(0, logger_1.log)(`Creating signing credential for user: ${username}`);
|
|
102
|
+
return await this.assertSigner().createSigningCredential(username);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
(0, logger_1.logError)(`Error creating signing credential: ${error.message}`);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* @inheritdoc
|
|
111
|
+
*/
|
|
112
|
+
createAuthenticator(credentialId) {
|
|
113
|
+
try {
|
|
114
|
+
(0, logger_1.log)(`Creating authenticator for credential: ${credentialId}`);
|
|
115
|
+
return this.assertSigner().createAuthenticator(credentialId);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
(0, logger_1.logError)(`Error creating authenticator: ${error.message}`);
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* @inheritdoc
|
|
124
|
+
*/
|
|
125
|
+
async createDerivedKeyPair(credentialId, username, extra) {
|
|
126
|
+
try {
|
|
127
|
+
(0, logger_1.log)(`Creating derived key pair for credential: ${credentialId}`);
|
|
128
|
+
return await this.assertSigner().createDerivedKeyPair(credentialId, username, extra);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
(0, logger_1.logError)(`Error creating derived key pair: ${error.message}`);
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* @inheritdoc
|
|
137
|
+
*/
|
|
138
|
+
async signWithDerivedKeys(data, credentialId, username, extra) {
|
|
139
|
+
try {
|
|
140
|
+
(0, logger_1.log)(`Signing data with derived keys for credential: ${credentialId}`);
|
|
141
|
+
return await this.assertSigner().signWithDerivedKeys(data, credentialId, username, extra);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
(0, logger_1.logError)(`Error signing with derived keys: ${error.message}`);
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* @inheritdoc
|
|
150
|
+
*/
|
|
151
|
+
getSigningCredential(credentialId) {
|
|
152
|
+
return this.assertSigner().getCredential(credentialId);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* @inheritdoc
|
|
156
|
+
*/
|
|
157
|
+
listSigningCredentials() {
|
|
158
|
+
return this.assertSigner().listCredentials();
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* @inheritdoc
|
|
162
|
+
*/
|
|
163
|
+
removeSigningCredential(credentialId) {
|
|
164
|
+
return this.assertSigner().removeCredential(credentialId);
|
|
165
|
+
}
|
|
166
|
+
// === CONSISTENCY METHODS ===
|
|
167
|
+
/**
|
|
168
|
+
* Creates a Gun user from WebAuthn signing credential
|
|
169
|
+
* This ensures the SAME user is created as with normal approach
|
|
170
|
+
*/
|
|
171
|
+
async createGunUserFromSigningCredential(credentialId, username) {
|
|
172
|
+
try {
|
|
173
|
+
const core = this.assertInitialized();
|
|
174
|
+
(0, logger_1.log)(`Creating Gun user from signing credential: ${credentialId}`);
|
|
175
|
+
return await this.assertSigner().createGunUser(credentialId, username, core.gun);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
(0, logger_1.logError)(`Error creating Gun user from signing credential: ${error.message}`);
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get the Gun user public key for a signing credential
|
|
184
|
+
*/
|
|
185
|
+
getGunUserPubFromSigningCredential(credentialId) {
|
|
186
|
+
return this.assertSigner().getGunUserPub(credentialId);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get the hashed credential ID (for consistency checking)
|
|
190
|
+
*/
|
|
191
|
+
getHashedCredentialId(credentialId) {
|
|
192
|
+
return this.assertSigner().getHashedCredentialId(credentialId);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Verify consistency between oneshot and normal approaches
|
|
196
|
+
* This ensures both approaches create the same Gun user
|
|
197
|
+
*/
|
|
198
|
+
async verifyConsistency(credentialId, username, expectedUserPub) {
|
|
199
|
+
try {
|
|
200
|
+
(0, logger_1.log)(`Verifying consistency for credential: ${credentialId}`);
|
|
201
|
+
return await this.assertSigner().verifyConsistency(credentialId, username, expectedUserPub);
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
(0, logger_1.logError)(`Error verifying consistency: ${error.message}`);
|
|
205
|
+
return { consistent: false };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Complete oneshot workflow that creates the SAME Gun user as normal approach
|
|
210
|
+
* This is the recommended method for oneshot signing with full consistency
|
|
211
|
+
*/
|
|
212
|
+
async setupConsistentOneshotSigning(username) {
|
|
213
|
+
try {
|
|
214
|
+
(0, logger_1.log)(`Setting up consistent oneshot signing for: ${username}`);
|
|
215
|
+
// 1. Create signing credential (with consistent hashing)
|
|
216
|
+
const credential = await this.createSigningCredential(username);
|
|
217
|
+
// 2. Create authenticator
|
|
218
|
+
const authenticator = this.createAuthenticator(credential.id);
|
|
219
|
+
// 3. Create Gun user (same as normal approach)
|
|
220
|
+
const gunUser = await this.createGunUserFromSigningCredential(credential.id, username);
|
|
221
|
+
return {
|
|
222
|
+
credential,
|
|
223
|
+
authenticator,
|
|
224
|
+
gunUser,
|
|
225
|
+
pub: credential.pub,
|
|
226
|
+
hashedCredentialId: credential.hashedCredentialId,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
(0, logger_1.logError)(`Error setting up consistent oneshot signing: ${error.message}`);
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
81
234
|
/**
|
|
82
235
|
* Login with WebAuthn
|
|
83
236
|
* This is the recommended method for WebAuthn authentication
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WebAuthnSigner = void 0;
|
|
7
|
+
const webauthn_1 = require("./webauthn");
|
|
8
|
+
const p256_1 = require("@noble/curves/p256");
|
|
9
|
+
const sha256_1 = require("@noble/hashes/sha256");
|
|
10
|
+
const logger_1 = require("../../utils/logger");
|
|
11
|
+
const derive_1 = __importDefault(require("../../gundb/derive"));
|
|
12
|
+
const ethers_1 = require("ethers");
|
|
13
|
+
/**
|
|
14
|
+
* Base64URL encoding utilities
|
|
15
|
+
*/
|
|
16
|
+
const base64url = {
|
|
17
|
+
encode: function (buffer) {
|
|
18
|
+
const bytes = new Uint8Array(buffer);
|
|
19
|
+
return btoa(String.fromCharCode(...bytes))
|
|
20
|
+
.replace(/\+/g, "-")
|
|
21
|
+
.replace(/\//g, "_")
|
|
22
|
+
.replace(/=/g, "");
|
|
23
|
+
},
|
|
24
|
+
decode: function (str) {
|
|
25
|
+
str = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
26
|
+
while (str.length % 4)
|
|
27
|
+
str += "=";
|
|
28
|
+
const binary = atob(str);
|
|
29
|
+
return new Uint8Array(binary.split("").map((c) => c.charCodeAt(0)));
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* WebAuthn Signer - Provides oneshot signing functionality
|
|
34
|
+
* Similar to webauthn.js but integrated with our architecture
|
|
35
|
+
* CONSISTENT with normal WebAuthn approach
|
|
36
|
+
*/
|
|
37
|
+
class WebAuthnSigner {
|
|
38
|
+
webauthn;
|
|
39
|
+
credentials = new Map();
|
|
40
|
+
constructor(webauthn) {
|
|
41
|
+
this.webauthn = webauthn || new webauthn_1.Webauthn();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Creates a new WebAuthn credential for signing
|
|
45
|
+
* Similar to webauthn.js create functionality but CONSISTENT with normal approach
|
|
46
|
+
*/
|
|
47
|
+
async createSigningCredential(username) {
|
|
48
|
+
try {
|
|
49
|
+
const credential = (await navigator.credentials.create({
|
|
50
|
+
publicKey: {
|
|
51
|
+
challenge: crypto.getRandomValues(new Uint8Array(32)),
|
|
52
|
+
rp: {
|
|
53
|
+
id: window.location.hostname === "localhost"
|
|
54
|
+
? "localhost"
|
|
55
|
+
: window.location.hostname,
|
|
56
|
+
name: "Shogun Wallet",
|
|
57
|
+
},
|
|
58
|
+
user: {
|
|
59
|
+
id: new TextEncoder().encode(username),
|
|
60
|
+
name: username,
|
|
61
|
+
displayName: username,
|
|
62
|
+
},
|
|
63
|
+
// Use the same algorithms as webauthn.js for SEA compatibility
|
|
64
|
+
pubKeyCredParams: [
|
|
65
|
+
{ type: "public-key", alg: -7 }, // ECDSA, P-256 curve, for signing
|
|
66
|
+
{ type: "public-key", alg: -25 }, // ECDH, P-256 curve, for creating shared secrets
|
|
67
|
+
{ type: "public-key", alg: -257 },
|
|
68
|
+
],
|
|
69
|
+
authenticatorSelection: {
|
|
70
|
+
userVerification: "preferred",
|
|
71
|
+
},
|
|
72
|
+
timeout: 60000,
|
|
73
|
+
attestation: "none",
|
|
74
|
+
},
|
|
75
|
+
}));
|
|
76
|
+
if (!credential) {
|
|
77
|
+
throw new Error("Failed to create WebAuthn credential");
|
|
78
|
+
}
|
|
79
|
+
// Extract public key in the same way as webauthn.js
|
|
80
|
+
const response = credential.response;
|
|
81
|
+
const publicKey = response.getPublicKey();
|
|
82
|
+
if (!publicKey) {
|
|
83
|
+
throw new Error("Failed to get public key from credential");
|
|
84
|
+
}
|
|
85
|
+
const rawKey = new Uint8Array(publicKey);
|
|
86
|
+
(0, logger_1.logDebug)("Raw public key bytes:", rawKey);
|
|
87
|
+
// Extract coordinates like webauthn.js (slice positions may need adjustment)
|
|
88
|
+
const xCoord = rawKey.slice(27, 59);
|
|
89
|
+
const yCoord = rawKey.slice(59, 91);
|
|
90
|
+
const x = base64url.encode(xCoord);
|
|
91
|
+
const y = base64url.encode(yCoord);
|
|
92
|
+
const pub = `${x}.${y}`;
|
|
93
|
+
// CONSISTENCY: Use the same hashing approach as normal WebAuthn
|
|
94
|
+
const hashedCredentialId = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(credential.id));
|
|
95
|
+
const signingCredential = {
|
|
96
|
+
id: credential.id,
|
|
97
|
+
rawId: credential.rawId,
|
|
98
|
+
publicKey: { x, y },
|
|
99
|
+
pub,
|
|
100
|
+
hashedCredentialId, // This ensures consistency
|
|
101
|
+
};
|
|
102
|
+
// Store credential for later use
|
|
103
|
+
this.credentials.set(credential.id, signingCredential);
|
|
104
|
+
(0, logger_1.logDebug)("Created signing credential:", signingCredential);
|
|
105
|
+
return signingCredential;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
(0, logger_1.logError)("Error creating signing credential:", error);
|
|
109
|
+
throw new Error(`Failed to create signing credential: ${error.message}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Creates an authenticator function compatible with SEA.sign
|
|
114
|
+
* This is the key function that makes it work like webauthn.js
|
|
115
|
+
*/
|
|
116
|
+
createAuthenticator(credentialId) {
|
|
117
|
+
const credential = this.credentials.get(credentialId);
|
|
118
|
+
if (!credential) {
|
|
119
|
+
throw new Error(`Credential ${credentialId} not found`);
|
|
120
|
+
}
|
|
121
|
+
return async (data) => {
|
|
122
|
+
try {
|
|
123
|
+
const challenge = new TextEncoder().encode(JSON.stringify(data));
|
|
124
|
+
const options = {
|
|
125
|
+
challenge,
|
|
126
|
+
rpId: window.location.hostname === "localhost"
|
|
127
|
+
? "localhost"
|
|
128
|
+
: window.location.hostname,
|
|
129
|
+
userVerification: "preferred",
|
|
130
|
+
allowCredentials: [
|
|
131
|
+
{
|
|
132
|
+
type: "public-key",
|
|
133
|
+
id: credential.rawId,
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
timeout: 60000,
|
|
137
|
+
};
|
|
138
|
+
const assertion = (await navigator.credentials.get({
|
|
139
|
+
publicKey: options,
|
|
140
|
+
}));
|
|
141
|
+
if (!assertion) {
|
|
142
|
+
throw new Error("WebAuthn assertion failed");
|
|
143
|
+
}
|
|
144
|
+
(0, logger_1.logDebug)("WebAuthn assertion successful:", { options, assertion });
|
|
145
|
+
return assertion.response;
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
(0, logger_1.logError)("WebAuthn assertion error:", error);
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Creates a derived key pair from WebAuthn credential
|
|
155
|
+
* CONSISTENT with normal approach: uses hashedCredentialId as password
|
|
156
|
+
*/
|
|
157
|
+
async createDerivedKeyPair(credentialId, username, extra) {
|
|
158
|
+
const credential = this.credentials.get(credentialId);
|
|
159
|
+
if (!credential) {
|
|
160
|
+
throw new Error(`Credential ${credentialId} not found`);
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
// CONSISTENCY: Use the same approach as normal WebAuthn
|
|
164
|
+
// Use hashedCredentialId as password (same as normal approach)
|
|
165
|
+
const derivedKeys = await (0, derive_1.default)(credential.hashedCredentialId, // This is the key change!
|
|
166
|
+
extra, { includeP256: true });
|
|
167
|
+
return {
|
|
168
|
+
pub: derivedKeys.pub,
|
|
169
|
+
priv: derivedKeys.priv,
|
|
170
|
+
epub: derivedKeys.epub,
|
|
171
|
+
epriv: derivedKeys.epriv,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
(0, logger_1.logError)("Error deriving keys from WebAuthn credential:", error);
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Creates a Gun user from WebAuthn credential
|
|
181
|
+
* This ensures the SAME user is created as with normal approach
|
|
182
|
+
*/
|
|
183
|
+
async createGunUser(credentialId, username, gunInstance) {
|
|
184
|
+
const credential = this.credentials.get(credentialId);
|
|
185
|
+
if (!credential) {
|
|
186
|
+
throw new Error(`Credential ${credentialId} not found`);
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
// Use the SAME approach as normal WebAuthn
|
|
190
|
+
return new Promise((resolve) => {
|
|
191
|
+
gunInstance
|
|
192
|
+
.user()
|
|
193
|
+
.create(username, credential.hashedCredentialId, (ack) => {
|
|
194
|
+
if (ack.err) {
|
|
195
|
+
// Try to login if user already exists
|
|
196
|
+
gunInstance
|
|
197
|
+
.user()
|
|
198
|
+
.auth(username, credential.hashedCredentialId, (authAck) => {
|
|
199
|
+
if (authAck.err) {
|
|
200
|
+
resolve({ success: false, error: authAck.err });
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
const userPub = authAck.pub;
|
|
204
|
+
// Update credential with Gun user pub
|
|
205
|
+
credential.gunUserPub = userPub;
|
|
206
|
+
this.credentials.set(credentialId, credential);
|
|
207
|
+
resolve({ success: true, userPub });
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// User created, now login
|
|
213
|
+
gunInstance
|
|
214
|
+
.user()
|
|
215
|
+
.auth(username, credential.hashedCredentialId, (authAck) => {
|
|
216
|
+
if (authAck.err) {
|
|
217
|
+
resolve({ success: false, error: authAck.err });
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const userPub = authAck.pub;
|
|
221
|
+
// Update credential with Gun user pub
|
|
222
|
+
credential.gunUserPub = userPub;
|
|
223
|
+
this.credentials.set(credentialId, credential);
|
|
224
|
+
resolve({ success: true, userPub });
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
(0, logger_1.logError)("Error creating Gun user:", error);
|
|
233
|
+
return { success: false, error: error.message };
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Signs data using WebAuthn + derived keys
|
|
238
|
+
* This provides a hybrid approach: WebAuthn for user verification + derived keys for actual signing
|
|
239
|
+
* CONSISTENT with normal approach
|
|
240
|
+
*/
|
|
241
|
+
async signWithDerivedKeys(data, credentialId, username, extra) {
|
|
242
|
+
try {
|
|
243
|
+
// First, verify user with WebAuthn
|
|
244
|
+
const authenticator = this.createAuthenticator(credentialId);
|
|
245
|
+
await authenticator(data); // This verifies the user
|
|
246
|
+
// Then use derived keys for actual signing (CONSISTENT approach)
|
|
247
|
+
const keyPair = await this.createDerivedKeyPair(credentialId, username, extra);
|
|
248
|
+
// Create signature using P-256 (same as SEA)
|
|
249
|
+
const message = JSON.stringify(data);
|
|
250
|
+
const messageHash = (0, sha256_1.sha256)(new TextEncoder().encode(message));
|
|
251
|
+
// Convert base64url private key to bytes
|
|
252
|
+
const privKeyBytes = base64url.decode(keyPair.priv);
|
|
253
|
+
// Sign with P-256
|
|
254
|
+
const signature = p256_1.p256.sign(messageHash, privKeyBytes);
|
|
255
|
+
// Format like SEA signature
|
|
256
|
+
const seaSignature = {
|
|
257
|
+
m: message,
|
|
258
|
+
s: base64url.encode(signature.toCompactRawBytes()),
|
|
259
|
+
};
|
|
260
|
+
return "SEA" + JSON.stringify(seaSignature);
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
(0, logger_1.logError)("Error signing with derived keys:", error);
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Get the Gun user public key for a credential
|
|
269
|
+
* This allows checking if the same user would be created
|
|
270
|
+
*/
|
|
271
|
+
getGunUserPub(credentialId) {
|
|
272
|
+
const credential = this.credentials.get(credentialId);
|
|
273
|
+
return credential?.gunUserPub;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get the hashed credential ID (for consistency checking)
|
|
277
|
+
*/
|
|
278
|
+
getHashedCredentialId(credentialId) {
|
|
279
|
+
const credential = this.credentials.get(credentialId);
|
|
280
|
+
return credential?.hashedCredentialId;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Check if this credential would create the same Gun user as normal approach
|
|
284
|
+
*/
|
|
285
|
+
async verifyConsistency(credentialId, username, expectedUserPub) {
|
|
286
|
+
const credential = this.credentials.get(credentialId);
|
|
287
|
+
if (!credential) {
|
|
288
|
+
return { consistent: false };
|
|
289
|
+
}
|
|
290
|
+
// The derived keys should be the same as normal approach
|
|
291
|
+
const derivedKeys = await this.createDerivedKeyPair(credentialId, username);
|
|
292
|
+
return {
|
|
293
|
+
consistent: expectedUserPub ? derivedKeys.pub === expectedUserPub : true,
|
|
294
|
+
actualUserPub: derivedKeys.pub,
|
|
295
|
+
expectedUserPub,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get credential by ID
|
|
300
|
+
*/
|
|
301
|
+
getCredential(credentialId) {
|
|
302
|
+
return this.credentials.get(credentialId);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* List all stored credentials
|
|
306
|
+
*/
|
|
307
|
+
listCredentials() {
|
|
308
|
+
return Array.from(this.credentials.values());
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Remove a credential
|
|
312
|
+
*/
|
|
313
|
+
removeCredential(credentialId) {
|
|
314
|
+
return this.credentials.delete(credentialId);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
exports.WebAuthnSigner = WebAuthnSigner;
|
|
318
|
+
exports.default = WebAuthnSigner;
|
package/dist/storage/storage.js
CHANGED
|
@@ -15,17 +15,13 @@ class ShogunStorage {
|
|
|
15
15
|
*/
|
|
16
16
|
constructor() {
|
|
17
17
|
this.store = new Map();
|
|
18
|
-
// Controlla se siamo in ambiente di test
|
|
19
18
|
this.isTestMode = process.env.NODE_ENV === "test";
|
|
20
19
|
this.useLocalStorage = false;
|
|
21
|
-
// Check if localStorage is available
|
|
22
20
|
if (typeof localStorage !== "undefined" && !this.isTestMode) {
|
|
23
21
|
try {
|
|
24
|
-
// Test localStorage access
|
|
25
22
|
localStorage.setItem("_shogun_test", "_shogun_test");
|
|
26
23
|
localStorage.removeItem("_shogun_test");
|
|
27
24
|
this.useLocalStorage = true;
|
|
28
|
-
// Load existing keypair if available
|
|
29
25
|
const storedPair = localStorage.getItem("shogun_keypair");
|
|
30
26
|
if (storedPair) {
|
|
31
27
|
this.store.set("keypair", JSON.parse(storedPair));
|
|
@@ -106,7 +102,6 @@ class ShogunStorage {
|
|
|
106
102
|
try {
|
|
107
103
|
const parsedValue = JSON.parse(value);
|
|
108
104
|
this.store.set(key, parsedValue);
|
|
109
|
-
// Also save to localStorage in browser environments
|
|
110
105
|
if (this.useLocalStorage) {
|
|
111
106
|
try {
|
|
112
107
|
localStorage.setItem(key, value);
|
|
@@ -119,9 +114,7 @@ class ShogunStorage {
|
|
|
119
114
|
}
|
|
120
115
|
}
|
|
121
116
|
catch (error) {
|
|
122
|
-
// If not valid JSON, store as string
|
|
123
117
|
this.store.set(key, value);
|
|
124
|
-
// Also save to localStorage in browser environments
|
|
125
118
|
if (this.useLocalStorage) {
|
|
126
119
|
try {
|
|
127
120
|
localStorage.setItem(key, value);
|
|
@@ -140,7 +133,6 @@ class ShogunStorage {
|
|
|
140
133
|
*/
|
|
141
134
|
removeItem(key) {
|
|
142
135
|
this.store.delete(key);
|
|
143
|
-
// Also remove from localStorage in browser environments
|
|
144
136
|
if (this.useLocalStorage) {
|
|
145
137
|
try {
|
|
146
138
|
localStorage.removeItem(key);
|
package/dist/types/core.d.ts
CHANGED
|
@@ -1,40 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GunInstance } from "./gundb";
|
|
2
2
|
import { GunRxJS } from "./gundb/rxjs-integration";
|
|
3
3
|
import { ShogunError } from "./utils/errorHandler";
|
|
4
4
|
import { ShogunStorage } from "./storage/storage";
|
|
5
5
|
import { IShogunCore, ShogunSDKConfig, AuthResult, SignUpResult, LoggingConfig, PluginCategory, AuthMethod } from "./types/shogun";
|
|
6
6
|
import { ethers } from "ethers";
|
|
7
7
|
import { ShogunPlugin } from "./types/plugin";
|
|
8
|
-
import { IGunUserInstance, IGunInstance } from "gun";
|
|
9
|
-
import "gun/sea";
|
|
10
|
-
export { RelayVerifier } from "./contracts/utils";
|
|
8
|
+
import { Gun, SEA, IGunUserInstance, IGunInstance } from "./gundb/gun-es/gun-es";
|
|
11
9
|
export * from "./utils/errorHandler";
|
|
10
|
+
export * from "./gundb";
|
|
12
11
|
export * from "./gundb/rxjs-integration";
|
|
13
12
|
export * from "./plugins";
|
|
14
|
-
export * from "./contracts/entryPoint";
|
|
15
|
-
export * from "./contracts/utils";
|
|
16
|
-
export * from "./contracts/registry";
|
|
17
|
-
export * from "./contracts/relay";
|
|
18
|
-
export type * from "./contracts/entryPoint";
|
|
19
|
-
export type * from "./contracts/relay";
|
|
20
|
-
export type * from "./contracts/registry";
|
|
21
|
-
export type * from "./contracts/base";
|
|
22
|
-
export type * from "./contracts/utils";
|
|
23
13
|
export type * from "./types/plugin";
|
|
24
14
|
export type * from "./utils/errorHandler";
|
|
15
|
+
export type { IGunUserInstance, IGunInstance } from "./gundb/gun-es/gun-es";
|
|
16
|
+
export { SEA, Gun };
|
|
25
17
|
export * from "./types/shogun";
|
|
26
|
-
export { GunDB } from "./gundb";
|
|
27
|
-
export { derive } from "./gundb";
|
|
28
|
-
export type { DeriveOptions } from "./gundb";
|
|
29
|
-
export { Web3Connector } from "./plugins/web3/web3Connector";
|
|
30
|
-
export { Webauthn } from "./plugins/webauthn/webauthn";
|
|
31
18
|
export { ShogunStorage } from "./storage/storage";
|
|
32
19
|
export { ShogunEventEmitter } from "./types/events";
|
|
33
20
|
/**
|
|
34
21
|
* Main ShogunCore class - implements the IShogunCore interface
|
|
35
22
|
*
|
|
36
23
|
* This is the primary entry point for the Shogun SDK, providing access to:
|
|
37
|
-
* - Decentralized database (
|
|
24
|
+
* - Decentralized database (GunInstance)
|
|
38
25
|
* - Authentication methods (traditional, WebAuthn, MetaMask)
|
|
39
26
|
* - Plugin system for extensibility
|
|
40
27
|
* - RxJS integration for reactive programming
|
|
@@ -42,33 +29,22 @@ export { ShogunEventEmitter } from "./types/events";
|
|
|
42
29
|
* @since 2.0.0
|
|
43
30
|
*/
|
|
44
31
|
export declare class ShogunCore implements IShogunCore {
|
|
45
|
-
/** Current API version - used for deprecation warnings and migration guidance */
|
|
46
32
|
static readonly API_VERSION = "2.0.0";
|
|
47
|
-
/** Gun database instance - access through gundb.gun for consistency */
|
|
48
33
|
private _gun;
|
|
49
|
-
/** Gun user instance */
|
|
50
34
|
private _user;
|
|
51
|
-
|
|
52
|
-
gundb: GunDB;
|
|
53
|
-
/** Storage implementation */
|
|
35
|
+
gundb: GunInstance;
|
|
54
36
|
storage: ShogunStorage;
|
|
55
|
-
/** Event emitter for SDK events */
|
|
56
37
|
private readonly eventEmitter;
|
|
57
|
-
/** Ethereum provider */
|
|
58
38
|
provider?: ethers.Provider;
|
|
59
|
-
/** SDK configuration */
|
|
60
39
|
config: ShogunSDKConfig;
|
|
61
|
-
/** RxJS integration */
|
|
62
40
|
rx: GunRxJS;
|
|
63
|
-
/** Plugin registry */
|
|
64
41
|
private readonly plugins;
|
|
65
|
-
/** Current authentication method */
|
|
66
42
|
private currentAuthMethod?;
|
|
67
43
|
/**
|
|
68
44
|
* Initialize the Shogun SDK
|
|
69
45
|
* @param config - SDK Configuration object
|
|
70
46
|
* @description Creates a new instance of ShogunCore with the provided configuration.
|
|
71
|
-
* Initializes all required components including storage, event emitter,
|
|
47
|
+
* Initializes all required components including storage, event emitter, GunInstance connection,
|
|
72
48
|
* and plugin system.
|
|
73
49
|
*/
|
|
74
50
|
constructor(config: ShogunSDKConfig);
|
|
@@ -145,13 +121,13 @@ export declare class ShogunCore implements IShogunCore {
|
|
|
145
121
|
/**
|
|
146
122
|
* Check if user is logged in
|
|
147
123
|
* @returns {boolean} True if user is logged in, false otherwise
|
|
148
|
-
* @description Verifies authentication status by checking
|
|
124
|
+
* @description Verifies authentication status by checking GunInstance login state
|
|
149
125
|
* and presence of authentication credentials in storage
|
|
150
126
|
*/
|
|
151
127
|
isLoggedIn(): boolean;
|
|
152
128
|
/**
|
|
153
129
|
* Perform user logout
|
|
154
|
-
* @description Logs out the current user from
|
|
130
|
+
* @description Logs out the current user from GunInstance and emits logout event.
|
|
155
131
|
* If user is not authenticated, the logout operation is ignored.
|
|
156
132
|
*/
|
|
157
133
|
logout(): void;
|
|
@@ -10,7 +10,7 @@ import * as GunErrors from "./errors";
|
|
|
10
10
|
import * as crypto from "./crypto";
|
|
11
11
|
import * as utils from "./utils";
|
|
12
12
|
import { DeriveOptions } from "./derive";
|
|
13
|
-
declare class
|
|
13
|
+
declare class GunInstance {
|
|
14
14
|
gun: IGunInstance<any>;
|
|
15
15
|
user: IGunUserInstance<any> | null;
|
|
16
16
|
crypto: typeof crypto;
|
|
@@ -256,4 +256,4 @@ declare class GunDB {
|
|
|
256
256
|
deriveAll(password: any, extra?: any): Promise<any>;
|
|
257
257
|
static Errors: typeof GunErrors;
|
|
258
258
|
}
|
|
259
|
-
export {
|
|
259
|
+
export { GunInstance };
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { GunInstance } from "./gunInstance";
|
|
2
2
|
export { Gun, SEA } from "./gun-es/gun-es";
|
|
3
|
-
export { default as derive } from "./derive";
|
|
4
|
-
export type { DeriveOptions } from "./derive";
|
|
5
|
-
export { getId, getPub, getTargetPub, getUUID, getSet, qs, getIndexedObjectFromArray, getArrayFromIndexedObject, app_scoped, } from "./utils";
|