jazz-react-native 0.8.44 → 0.8.47
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +26 -0
- package/dist/auth/DemoAuthMethod.d.ts +2 -1
- package/dist/auth/DemoAuthMethod.js +60 -25
- package/dist/auth/DemoAuthMethod.js.map +1 -1
- package/dist/auth/DemoAuthUI.d.ts +3 -1
- package/dist/auth/DemoAuthUI.js +13 -4
- package/dist/auth/DemoAuthUI.js.map +1 -1
- package/dist/crypto/RNQuickCrypto.d.ts +12 -0
- package/dist/crypto/RNQuickCrypto.js +31 -0
- package/dist/crypto/RNQuickCrypto.js.map +1 -0
- package/dist/crypto/index.d.ts +1 -0
- package/dist/crypto/index.js +2 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +52 -21
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +5 -5
- package/dist/provider.js +3 -1
- package/dist/provider.js.map +1 -1
- package/dist/tests/DemoAuthMethod.test.d.ts +1 -0
- package/dist/tests/DemoAuthMethod.test.js +186 -0
- package/dist/tests/DemoAuthMethod.test.js.map +1 -0
- package/package.json +11 -6
- package/src/auth/DemoAuthMethod.ts +79 -42
- package/src/auth/DemoAuthUI.tsx +14 -2
- package/src/crypto/RNQuickCrypto.ts +58 -0
- package/src/crypto/index.ts +1 -0
- package/src/index.ts +60 -25
- package/src/provider.tsx +8 -0
- package/src/tests/DemoAuthMethod.test.ts +282 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
2
|
+
import { RNDemoAuth } from "../auth/DemoAuthMethod";
|
3
|
+
import { KvStoreContext } from "../storage/kv-store-context";
|
4
|
+
// Initialize mock storage
|
5
|
+
const mockStorage = {};
|
6
|
+
// Mock KvStore implementation
|
7
|
+
const mockKvStore = {
|
8
|
+
get: vi.fn(async (key) => mockStorage[key] || null),
|
9
|
+
set: vi.fn(async (key, value) => {
|
10
|
+
mockStorage[key] = value;
|
11
|
+
}),
|
12
|
+
delete: vi.fn(async (key) => {
|
13
|
+
delete mockStorage[key];
|
14
|
+
}),
|
15
|
+
clearAll: vi.fn(async () => {
|
16
|
+
Object.keys(mockStorage).forEach((key) => delete mockStorage[key]);
|
17
|
+
}),
|
18
|
+
};
|
19
|
+
KvStoreContext.getInstance().initialize(mockKvStore);
|
20
|
+
beforeEach(() => {
|
21
|
+
mockKvStore.clearAll();
|
22
|
+
vi.clearAllMocks();
|
23
|
+
});
|
24
|
+
function setup() {
|
25
|
+
const mockDriver = {
|
26
|
+
onReady: vi.fn(),
|
27
|
+
onSignedIn: vi.fn(),
|
28
|
+
onError: vi.fn(),
|
29
|
+
};
|
30
|
+
return {
|
31
|
+
mockStorage,
|
32
|
+
mockKvStore,
|
33
|
+
mockDriver,
|
34
|
+
};
|
35
|
+
}
|
36
|
+
describe("RNDemoAuth", () => {
|
37
|
+
describe("initialization", () => {
|
38
|
+
it("should initialize with seed accounts", async () => {
|
39
|
+
const { mockKvStore, mockDriver } = setup();
|
40
|
+
const seedAccounts = {
|
41
|
+
testUser: {
|
42
|
+
accountID: "test-account-id",
|
43
|
+
accountSecret: "test-secret",
|
44
|
+
},
|
45
|
+
};
|
46
|
+
await RNDemoAuth.init(mockDriver, seedAccounts);
|
47
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users", "testUser");
|
48
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users-" + btoa("testUser"), expect.any(String));
|
49
|
+
});
|
50
|
+
});
|
51
|
+
describe("authentication", () => {
|
52
|
+
it("should handle new user signup", async () => {
|
53
|
+
const { mockDriver } = setup();
|
54
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
55
|
+
signUp("testUser");
|
56
|
+
});
|
57
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
58
|
+
const result = await auth.start();
|
59
|
+
expect(mockDriver.onReady).toHaveBeenCalled();
|
60
|
+
expect(result.type).toBe("new");
|
61
|
+
expect(result.saveCredentials).toBeDefined();
|
62
|
+
});
|
63
|
+
it("should handle existing user login", async () => {
|
64
|
+
const { mockStorage, mockDriver } = setup();
|
65
|
+
// Set up existing user in storage
|
66
|
+
const existingUser = {
|
67
|
+
accountID: "test-account-id",
|
68
|
+
accountSecret: "test-secret",
|
69
|
+
};
|
70
|
+
mockStorage["demo-auth-logged-in-secret"] = JSON.stringify(existingUser);
|
71
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
72
|
+
const result = await auth.start();
|
73
|
+
if (result.type !== "existing") {
|
74
|
+
throw new Error("Result is not a existing user");
|
75
|
+
}
|
76
|
+
expect(result.type).toBe("existing");
|
77
|
+
expect(result.credentials).toEqual({
|
78
|
+
accountID: existingUser.accountID,
|
79
|
+
secret: existingUser.accountSecret,
|
80
|
+
});
|
81
|
+
});
|
82
|
+
it("should handle logout", async () => {
|
83
|
+
const { mockKvStore, mockDriver } = setup();
|
84
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
85
|
+
signUp("testUser");
|
86
|
+
});
|
87
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
88
|
+
const result = await auth.start();
|
89
|
+
await result.logOut();
|
90
|
+
expect(mockKvStore.delete).toHaveBeenCalledWith("demo-auth-logged-in-secret");
|
91
|
+
});
|
92
|
+
});
|
93
|
+
describe("user management", () => {
|
94
|
+
it("should signup a new user", async () => {
|
95
|
+
const { mockKvStore, mockDriver } = setup();
|
96
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
97
|
+
return signUp("testUser");
|
98
|
+
});
|
99
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
100
|
+
const result = await auth.start();
|
101
|
+
if (result.type !== "new") {
|
102
|
+
throw new Error("Result is not a new user");
|
103
|
+
}
|
104
|
+
await result.saveCredentials({
|
105
|
+
accountID: "test-account-id",
|
106
|
+
secret: "test-secret",
|
107
|
+
});
|
108
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users-" + btoa("testUser"), expect.any(String));
|
109
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users", "testUser");
|
110
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-logged-in-secret", expect.any(String));
|
111
|
+
});
|
112
|
+
it("should login an existing user", async () => {
|
113
|
+
const { mockStorage, mockKvStore, mockDriver } = setup();
|
114
|
+
const credentials = {
|
115
|
+
accountID: "test-account-id",
|
116
|
+
accountSecret: "test-secret",
|
117
|
+
};
|
118
|
+
mockStorage["demo-auth-existing-users-" + btoa("testUser")] =
|
119
|
+
JSON.stringify(credentials);
|
120
|
+
mockDriver.onReady = vi.fn(({ logInAs }) => {
|
121
|
+
return logInAs("testUser");
|
122
|
+
});
|
123
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
124
|
+
const result = await auth.start();
|
125
|
+
if (result.type !== "existing") {
|
126
|
+
throw new Error("Result is not a existing user");
|
127
|
+
}
|
128
|
+
expect(result.credentials).toEqual({
|
129
|
+
accountID: credentials.accountID,
|
130
|
+
secret: credentials.accountSecret,
|
131
|
+
});
|
132
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-logged-in-secret", JSON.stringify(credentials));
|
133
|
+
});
|
134
|
+
it("should handle duplicate usernames by adding suffix", async () => {
|
135
|
+
const { mockStorage, mockKvStore, mockDriver } = setup();
|
136
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
137
|
+
return signUp("testUser");
|
138
|
+
});
|
139
|
+
mockStorage["demo-auth-existing-users"] = "testUser";
|
140
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
141
|
+
const result = await auth.start();
|
142
|
+
if (result.type !== "new") {
|
143
|
+
throw new Error("Result is not a new user");
|
144
|
+
}
|
145
|
+
await result.saveCredentials({
|
146
|
+
accountID: "test-account-id",
|
147
|
+
secret: "test-secret",
|
148
|
+
});
|
149
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users-" + btoa("testUser-2"), expect.any(String));
|
150
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users", "testUser,testUser-2");
|
151
|
+
});
|
152
|
+
it("should retrieve existing users", async () => {
|
153
|
+
const { mockStorage, mockDriver } = setup();
|
154
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
155
|
+
return signUp("testUser");
|
156
|
+
});
|
157
|
+
mockStorage["demo-auth-existing-users"] = "user1,user2,user3";
|
158
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
159
|
+
const result = await auth.start();
|
160
|
+
if (result.type !== "new") {
|
161
|
+
throw new Error("Result is not a new user");
|
162
|
+
}
|
163
|
+
await result.saveCredentials({
|
164
|
+
accountID: "test-account-id",
|
165
|
+
secret: "test-secret",
|
166
|
+
});
|
167
|
+
const onReadyCall = vi.mocked(mockDriver.onReady).mock.calls[0][0];
|
168
|
+
const existingUsers = await onReadyCall.getExistingUsers();
|
169
|
+
expect(existingUsers).toEqual(["user1", "user2", "user3", "testUser"]);
|
170
|
+
});
|
171
|
+
it("should migrate legacy user keys to the new format", async () => {
|
172
|
+
const { mockStorage, mockKvStore, mockDriver } = setup();
|
173
|
+
const value = JSON.stringify({
|
174
|
+
accountID: "test-account-id",
|
175
|
+
accountSecret: "test-secret",
|
176
|
+
});
|
177
|
+
mockStorage["demo-auth-existing-users"] = "testUser";
|
178
|
+
mockStorage["demo-auth-existing-users-testUser"] = value;
|
179
|
+
await RNDemoAuth.init(mockDriver);
|
180
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users-" + btoa("testUser"), value);
|
181
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-storage-version", "2");
|
182
|
+
expect(mockKvStore.delete).toHaveBeenCalledWith("demo-auth-existing-users-testUser");
|
183
|
+
});
|
184
|
+
});
|
185
|
+
});
|
186
|
+
//# sourceMappingURL=DemoAuthMethod.test.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"DemoAuthMethod.test.js","sourceRoot":"","sources":["../../src/tests/DemoAuthMethod.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "jazz-react-native",
|
3
|
-
"version": "0.8.
|
3
|
+
"version": "0.8.47",
|
4
4
|
"type": "module",
|
5
5
|
"main": "./dist/index.js",
|
6
6
|
"module": "./dist/index.js",
|
@@ -11,24 +11,29 @@
|
|
11
11
|
"react-native": "./dist/index.js",
|
12
12
|
"types": "./dist/index.d.ts",
|
13
13
|
"default": "./dist/index.js"
|
14
|
+
},
|
15
|
+
"./crypto": {
|
16
|
+
"react-native": "./dist/crypto/index.js",
|
17
|
+
"types": "./dist/crypto/index.d.ts",
|
18
|
+
"default": "./dist/crypto/index.js"
|
14
19
|
}
|
15
20
|
},
|
16
21
|
"license": "MIT",
|
17
22
|
"dependencies": {
|
23
|
+
"@scure/base": "1.2.1",
|
18
24
|
"@scure/bip39": "^1.3.0",
|
19
|
-
"
|
20
|
-
"cojson
|
21
|
-
"
|
25
|
+
"react-native-quick-crypto": "1.0.0-beta.9",
|
26
|
+
"cojson": "0.8.45",
|
27
|
+
"cojson-transport-ws": "0.8.45",
|
28
|
+
"jazz-tools": "0.8.45"
|
22
29
|
},
|
23
30
|
"peerDependencies": {
|
24
31
|
"@react-native-community/netinfo": "*",
|
25
|
-
"expo-linking": "*",
|
26
32
|
"expo-secure-store": "*",
|
27
33
|
"react-native": "*"
|
28
34
|
},
|
29
35
|
"devDependencies": {
|
30
36
|
"@react-native-community/netinfo": "^11.4.1",
|
31
|
-
"expo-linking": "~7.0.3",
|
32
37
|
"expo-secure-store": "~14.0.0",
|
33
38
|
"react-native": "~0.76.3",
|
34
39
|
"typescript": "~5.6.2"
|
@@ -23,6 +23,69 @@ export namespace RNDemoAuth {
|
|
23
23
|
|
24
24
|
const localStorageKey = "demo-auth-logged-in-secret";
|
25
25
|
|
26
|
+
function getUserStorageKey(username: string) {
|
27
|
+
return `demo-auth-existing-users-${btoa(username)}`;
|
28
|
+
}
|
29
|
+
|
30
|
+
function getLegacyUserStorageKey(username: string) {
|
31
|
+
return `demo-auth-existing-users-${username}`;
|
32
|
+
}
|
33
|
+
|
34
|
+
async function getStorageVersion(kvStore: KvStore) {
|
35
|
+
try {
|
36
|
+
const version = await kvStore.get("demo-auth-storage-version");
|
37
|
+
return version ? parseInt(version) : 1;
|
38
|
+
} catch (error) {
|
39
|
+
return 1;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
async function setStorageVersion(kvStore: KvStore, version: number) {
|
44
|
+
await kvStore.set("demo-auth-storage-version", version.toString());
|
45
|
+
}
|
46
|
+
|
47
|
+
async function getExistingUsers(kvStore: KvStore) {
|
48
|
+
const existingUsers = await kvStore.get("demo-auth-existing-users");
|
49
|
+
return existingUsers ? existingUsers.split(",") : [];
|
50
|
+
}
|
51
|
+
|
52
|
+
async function addUserToExistingUsers(username: string, kvStore: KvStore) {
|
53
|
+
const existingUsers = await getExistingUsers(kvStore);
|
54
|
+
|
55
|
+
if (existingUsers.includes(username)) {
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
|
59
|
+
await kvStore.set(
|
60
|
+
"demo-auth-existing-users",
|
61
|
+
existingUsers.concat(username).join(","),
|
62
|
+
);
|
63
|
+
}
|
64
|
+
|
65
|
+
/**
|
66
|
+
* Migrates existing users keys to use a base64 encoded username.
|
67
|
+
*
|
68
|
+
* This is done to avoid issues with special characters in the username.
|
69
|
+
*/
|
70
|
+
async function migrateExistingUsersKeys(kvStore: KvStore) {
|
71
|
+
if ((await getStorageVersion(kvStore)) >= 2) {
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
|
75
|
+
await setStorageVersion(kvStore, 2);
|
76
|
+
|
77
|
+
const existingUsers = await getExistingUsers(kvStore);
|
78
|
+
|
79
|
+
for (const existingUsername of existingUsers) {
|
80
|
+
const legacyKey = getLegacyUserStorageKey(existingUsername);
|
81
|
+
const storageData = await kvStore.get(legacyKey);
|
82
|
+
if (storageData) {
|
83
|
+
await kvStore.set(getUserStorageKey(existingUsername), storageData);
|
84
|
+
await kvStore.delete(legacyKey);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
26
89
|
export class RNDemoAuth implements AuthMethod {
|
27
90
|
private constructor(
|
28
91
|
private driver: RNDemoAuth.Driver,
|
@@ -37,29 +100,19 @@ export class RNDemoAuth implements AuthMethod {
|
|
37
100
|
accountSecret: AgentSecret;
|
38
101
|
};
|
39
102
|
},
|
103
|
+
store?: KvStore | undefined,
|
40
104
|
) {
|
41
|
-
const kvStore = KvStoreContext.getInstance().getStorage();
|
105
|
+
const kvStore = store ? store : KvStoreContext.getInstance().getStorage();
|
106
|
+
|
107
|
+
await migrateExistingUsersKeys(kvStore);
|
108
|
+
|
42
109
|
for (const [name, credentials] of Object.entries(seedAccounts || {})) {
|
43
110
|
const storageData = JSON.stringify(credentials satisfies StorageData);
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
| string[]
|
48
|
-
| undefined
|
49
|
-
)?.includes(name)
|
50
|
-
) {
|
51
|
-
const existingUsers = await kvStore.get("demo-auth-existing-users");
|
52
|
-
if (existingUsers) {
|
53
|
-
await kvStore.set(
|
54
|
-
"demo-auth-existing-users",
|
55
|
-
existingUsers + "," + name,
|
56
|
-
);
|
57
|
-
} else {
|
58
|
-
await kvStore.set("demo-auth-existing-users", name);
|
59
|
-
}
|
60
|
-
}
|
61
|
-
await kvStore.set("demo-auth-existing-users-" + name, storageData);
|
111
|
+
|
112
|
+
await addUserToExistingUsers(name, kvStore);
|
113
|
+
await kvStore.set(getUserStorageKey(name), storageData);
|
62
114
|
}
|
115
|
+
|
63
116
|
return new RNDemoAuth(driver, kvStore);
|
64
117
|
}
|
65
118
|
|
@@ -103,13 +156,9 @@ export class RNDemoAuth implements AuthMethod {
|
|
103
156
|
accountSecret: credentials.secret,
|
104
157
|
} satisfies StorageData);
|
105
158
|
|
106
|
-
|
107
|
-
|
108
|
-
"demo-auth-existing-users",
|
159
|
+
const existingUsernames = await getExistingUsers(
|
160
|
+
this.kvStore,
|
109
161
|
);
|
110
|
-
const existingUsernames = existingUsers
|
111
|
-
? existingUsers.split(",")
|
112
|
-
: [];
|
113
162
|
|
114
163
|
// Determine if the username already exists and generate a unique username
|
115
164
|
let uniqueUsername = username;
|
@@ -122,18 +171,11 @@ export class RNDemoAuth implements AuthMethod {
|
|
122
171
|
// Save credentials using the unique username
|
123
172
|
await this.kvStore.set(localStorageKey, storageData);
|
124
173
|
await this.kvStore.set(
|
125
|
-
|
174
|
+
getUserStorageKey(uniqueUsername),
|
126
175
|
storageData,
|
127
176
|
);
|
128
177
|
|
129
|
-
|
130
|
-
const updatedUsers = existingUsers
|
131
|
-
? `${existingUsers},${uniqueUsername}`
|
132
|
-
: uniqueUsername;
|
133
|
-
await this.kvStore.set(
|
134
|
-
"demo-auth-existing-users",
|
135
|
-
updatedUsers,
|
136
|
-
);
|
178
|
+
await addUserToExistingUsers(uniqueUsername, this.kvStore);
|
137
179
|
},
|
138
180
|
onSuccess: () => {
|
139
181
|
this.driver.onSignedIn({ logOut });
|
@@ -149,17 +191,12 @@ export class RNDemoAuth implements AuthMethod {
|
|
149
191
|
});
|
150
192
|
},
|
151
193
|
getExistingUsers: async () => {
|
152
|
-
return (
|
153
|
-
(await this.kvStore.get("demo-auth-existing-users"))?.split(
|
154
|
-
",",
|
155
|
-
) ?? []
|
156
|
-
);
|
194
|
+
return await getExistingUsers(this.kvStore);
|
157
195
|
},
|
158
196
|
logInAs: async (existingUser) => {
|
159
197
|
const storageData = JSON.parse(
|
160
|
-
(await this.kvStore.get(
|
161
|
-
"
|
162
|
-
)) ?? "{}",
|
198
|
+
(await this.kvStore.get(getUserStorageKey(existingUser))) ??
|
199
|
+
"{}",
|
163
200
|
) as StorageData;
|
164
201
|
|
165
202
|
await this.kvStore.set(
|
package/src/auth/DemoAuthUI.tsx
CHANGED
@@ -8,6 +8,7 @@ import {
|
|
8
8
|
TouchableOpacity,
|
9
9
|
View,
|
10
10
|
} from "react-native";
|
11
|
+
import { KvStore } from "../storage/kv-store-context.js";
|
11
12
|
import { RNDemoAuth } from "./DemoAuthMethod.js";
|
12
13
|
|
13
14
|
type DemoAuthState = (
|
@@ -34,10 +35,12 @@ type DemoAuthState = (
|
|
34
35
|
/** @category Auth Providers */
|
35
36
|
export function useDemoAuth({
|
36
37
|
seedAccounts,
|
38
|
+
store,
|
37
39
|
}: {
|
38
40
|
seedAccounts?: {
|
39
41
|
[name: string]: { accountID: ID<Account>; accountSecret: AgentSecret };
|
40
42
|
};
|
43
|
+
store?: KvStore;
|
41
44
|
} = {}) {
|
42
45
|
const [state, setState] = useState<DemoAuthState>({
|
43
46
|
state: "loading",
|
@@ -70,13 +73,22 @@ export function useDemoAuth({
|
|
70
73
|
},
|
71
74
|
},
|
72
75
|
seedAccounts,
|
76
|
+
store,
|
73
77
|
);
|
74
78
|
}, [seedAccounts]);
|
75
79
|
|
76
80
|
useEffect(() => {
|
77
81
|
async function init() {
|
78
|
-
|
79
|
-
|
82
|
+
try {
|
83
|
+
const auth = await authMethodPromise;
|
84
|
+
setAuthMethod(auth);
|
85
|
+
} catch (e: unknown) {
|
86
|
+
const err = e as Error;
|
87
|
+
setState((current) => ({
|
88
|
+
...current,
|
89
|
+
errors: [...current.errors, err.toString()],
|
90
|
+
}));
|
91
|
+
}
|
80
92
|
}
|
81
93
|
if (authMethod) return;
|
82
94
|
void init();
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import { base58 } from "@scure/base";
|
2
|
+
import { JsonValue, PureJSCrypto } from "cojson/native";
|
3
|
+
import { CojsonInternalTypes, cojsonInternals } from "cojson/native";
|
4
|
+
import { Ed } from "react-native-quick-crypto";
|
5
|
+
const { stableStringify } = cojsonInternals;
|
6
|
+
|
7
|
+
const textEncoder = new TextEncoder();
|
8
|
+
|
9
|
+
export class RNQuickCrypto extends PureJSCrypto {
|
10
|
+
ed: Ed;
|
11
|
+
|
12
|
+
constructor() {
|
13
|
+
super();
|
14
|
+
this.ed = new Ed("ed25519", {});
|
15
|
+
}
|
16
|
+
|
17
|
+
static async create(): Promise<RNQuickCrypto> {
|
18
|
+
return new RNQuickCrypto();
|
19
|
+
}
|
20
|
+
|
21
|
+
newEd25519SigningKey(): Uint8Array {
|
22
|
+
this.ed.generateKeyPairSync();
|
23
|
+
return new Uint8Array(this.ed.getPrivateKey());
|
24
|
+
}
|
25
|
+
|
26
|
+
getSignerID(
|
27
|
+
secret: CojsonInternalTypes.SignerSecret,
|
28
|
+
): CojsonInternalTypes.SignerID {
|
29
|
+
return `signer_z${base58.encode(
|
30
|
+
base58.decode(secret.substring("signerSecret_z".length)),
|
31
|
+
)}`;
|
32
|
+
}
|
33
|
+
|
34
|
+
sign(
|
35
|
+
secret: CojsonInternalTypes.SignerSecret,
|
36
|
+
message: JsonValue,
|
37
|
+
): CojsonInternalTypes.Signature {
|
38
|
+
const signature = new Uint8Array(
|
39
|
+
this.ed.signSync(
|
40
|
+
textEncoder.encode(stableStringify(message)),
|
41
|
+
base58.decode(secret.substring("signerSecret_z".length)),
|
42
|
+
),
|
43
|
+
);
|
44
|
+
return `signature_z${base58.encode(signature)}`;
|
45
|
+
}
|
46
|
+
|
47
|
+
verify(
|
48
|
+
signature: CojsonInternalTypes.Signature,
|
49
|
+
message: JsonValue,
|
50
|
+
id: CojsonInternalTypes.SignerID,
|
51
|
+
): boolean {
|
52
|
+
return this.ed.verifySync(
|
53
|
+
base58.decode(signature.substring("signature_z".length)),
|
54
|
+
textEncoder.encode(stableStringify(message)),
|
55
|
+
base58.decode(id.substring("signer_z".length)),
|
56
|
+
);
|
57
|
+
}
|
58
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export { RNQuickCrypto } from "./RNQuickCrypto.js";
|
package/src/index.ts
CHANGED
@@ -15,15 +15,13 @@ import {
|
|
15
15
|
createJazzContext,
|
16
16
|
} from "jazz-tools";
|
17
17
|
|
18
|
-
import NetInfo from "@react-native-community/netinfo";
|
19
18
|
import { RawAccountID } from "cojson";
|
20
|
-
import { createWebSocketPeer } from "cojson-transport-ws";
|
21
|
-
import * as Linking from "expo-linking";
|
22
|
-
import { PureJSCrypto } from "jazz-tools/native";
|
23
19
|
|
24
20
|
export { RNDemoAuth } from "./auth/DemoAuthMethod.js";
|
25
21
|
|
22
|
+
import { PureJSCrypto } from "cojson/native";
|
26
23
|
import { createWebSocketPeerWithReconnection } from "./createWebSocketPeerWithReconnection.js";
|
24
|
+
import type { RNQuickCrypto } from "./crypto/RNQuickCrypto.js";
|
27
25
|
import { KvStoreContext } from "./storage/kv-store-context.js";
|
28
26
|
|
29
27
|
/** @category Context Creation */
|
@@ -51,7 +49,7 @@ export type BaseReactNativeContextOptions = {
|
|
51
49
|
peer: `wss://${string}` | `ws://${string}`;
|
52
50
|
reconnectionTimeout?: number;
|
53
51
|
storage?: "indexedDB" | "singleTabOPFS";
|
54
|
-
|
52
|
+
CryptoProvider?: typeof PureJSCrypto | typeof RNQuickCrypto;
|
55
53
|
};
|
56
54
|
|
57
55
|
/** @category Context Creation */
|
@@ -75,17 +73,19 @@ export async function createJazzRNContext<Acc extends Account>(
|
|
75
73
|
},
|
76
74
|
);
|
77
75
|
|
76
|
+
const CryptoProvider = options.CryptoProvider || PureJSCrypto;
|
77
|
+
|
78
78
|
const context =
|
79
79
|
"auth" in options
|
80
80
|
? await createJazzContext({
|
81
81
|
AccountSchema: options.AccountSchema,
|
82
82
|
auth: options.auth,
|
83
|
-
crypto: await
|
83
|
+
crypto: await CryptoProvider.create(),
|
84
84
|
peersToLoadFrom: [websocketPeer.peer],
|
85
85
|
sessionProvider: provideLockSession,
|
86
86
|
})
|
87
87
|
: await createJazzContext({
|
88
|
-
crypto: await
|
88
|
+
crypto: await CryptoProvider.create(),
|
89
89
|
peersToLoadFrom: [websocketPeer.peer],
|
90
90
|
});
|
91
91
|
|
@@ -165,6 +165,7 @@ export function createInviteLink<C extends CoValue>(
|
|
165
165
|
}
|
166
166
|
|
167
167
|
/** @category Invite Links */
|
168
|
+
// TODO: copied from jazz-browser, should be shared
|
168
169
|
export function parseInviteLink<C extends CoValue>(
|
169
170
|
inviteURL: string,
|
170
171
|
):
|
@@ -174,33 +175,67 @@ export function parseInviteLink<C extends CoValue>(
|
|
174
175
|
inviteSecret: InviteSecret;
|
175
176
|
}
|
176
177
|
| undefined {
|
177
|
-
const url =
|
178
|
-
const parts = url.
|
179
|
-
|
180
|
-
if (!parts || parts[0] !== "invite") {
|
181
|
-
return undefined;
|
182
|
-
}
|
178
|
+
const url = new URL(inviteURL);
|
179
|
+
const parts = url.hash.split("/");
|
183
180
|
|
184
181
|
let valueHint: string | undefined;
|
185
182
|
let valueID: ID<C> | undefined;
|
186
183
|
let inviteSecret: InviteSecret | undefined;
|
187
184
|
|
188
|
-
if (parts
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
185
|
+
if (parts[0] === "#" && parts[1] === "invite") {
|
186
|
+
if (parts.length === 5) {
|
187
|
+
valueHint = parts[2];
|
188
|
+
valueID = parts[3] as ID<C>;
|
189
|
+
inviteSecret = parts[4] as InviteSecret;
|
190
|
+
} else if (parts.length === 4) {
|
191
|
+
valueID = parts[2] as ID<C>;
|
192
|
+
inviteSecret = parts[3] as InviteSecret;
|
193
|
+
}
|
196
194
|
|
197
|
-
|
198
|
-
|
195
|
+
if (!valueID || !inviteSecret) {
|
196
|
+
return undefined;
|
197
|
+
}
|
198
|
+
return { valueID, inviteSecret, valueHint };
|
199
199
|
}
|
200
|
-
|
201
|
-
return { valueID, inviteSecret, valueHint };
|
202
200
|
}
|
203
201
|
|
202
|
+
// getting out of the `expo` business 🤞
|
203
|
+
// export function parseInviteLink<C extends CoValue>(
|
204
|
+
// inviteURL: string,
|
205
|
+
// ):
|
206
|
+
// | {
|
207
|
+
// valueID: ID<C>;
|
208
|
+
// valueHint?: string;
|
209
|
+
// inviteSecret: InviteSecret;
|
210
|
+
// }
|
211
|
+
// | undefined {
|
212
|
+
// const url = Linking.parse(inviteURL);
|
213
|
+
// const parts = url.path?.split("/");
|
214
|
+
|
215
|
+
// if (!parts || parts[0] !== "invite") {
|
216
|
+
// return undefined;
|
217
|
+
// }
|
218
|
+
|
219
|
+
// let valueHint: string | undefined;
|
220
|
+
// let valueID: ID<C> | undefined;
|
221
|
+
// let inviteSecret: InviteSecret | undefined;
|
222
|
+
|
223
|
+
// if (parts.length === 4) {
|
224
|
+
// valueHint = parts[1];
|
225
|
+
// valueID = parts[2] as ID<C>;
|
226
|
+
// inviteSecret = parts[3] as InviteSecret;
|
227
|
+
// } else if (parts.length === 3) {
|
228
|
+
// valueID = parts[1] as ID<C>;
|
229
|
+
// inviteSecret = parts[2] as InviteSecret;
|
230
|
+
// }
|
231
|
+
|
232
|
+
// if (!valueID || !inviteSecret) {
|
233
|
+
// return undefined;
|
234
|
+
// }
|
235
|
+
|
236
|
+
// return { valueID, inviteSecret, valueHint };
|
237
|
+
// }
|
238
|
+
|
204
239
|
/////////
|
205
240
|
|
206
241
|
export * from "./provider.js";
|