@octane-xplat/auth 0.10.0 → 0.11.0
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 +65 -1
- package/dist/native/auth/src/base64.js +17 -0
- package/dist/native/auth/src/hosted.js +252 -0
- package/dist/native/auth/src/sha256.js +141 -0
- package/dist/native/index.js +6 -5
- package/dist/native/octane-client-build.json +1 -1
- package/dist/native/platform/src/a11y.js +1 -0
- package/dist/native/platform/src/app-info.js +1 -0
- package/dist/native/platform/src/auth-session.js +138 -0
- package/dist/native/platform/src/breakpoints.tsrx.js +5 -0
- package/dist/native/platform/src/clipboard.js +1 -0
- package/dist/native/platform/src/connectivity.js +1 -0
- package/dist/native/platform/src/deep-links.js +1 -0
- package/dist/native/platform/src/device.js +3 -0
- package/dist/native/platform/src/index.js +17 -0
- package/dist/native/platform/src/lifecycle.tsrx.js +7 -0
- package/dist/native/platform/src/locale.js +3 -0
- package/dist/native/platform/src/open-url.js +1 -0
- package/dist/native/platform/src/random.js +38 -0
- package/dist/native/platform/src/safe-area.tsrx.js +4 -0
- package/dist/native/platform/src/screen.tsrx.js +4 -0
- package/dist/native/platform/src/storage.js +1 -0
- package/dist/native/platform/src/system-bars.js +1 -0
- package/dist/native/secure-storage/src/index.js +2 -0
- package/dist/native/secure-storage/src/secure-storage.js +17 -0
- package/dist/web/auth/src/base64.js +17 -0
- package/dist/web/auth/src/hosted.js +251 -0
- package/dist/web/auth/src/sha256.js +141 -0
- package/dist/web/index.js +6 -5
- package/dist/web/octane-client-build.json +1 -1
- package/dist/web/platform/src/app-info.web.js +3 -0
- package/dist/web/platform/src/auth-session.web.js +10 -0
- package/dist/web/platform/src/breakpoints.web.tsrx.js +7 -0
- package/dist/web/platform/src/clipboard.web.js +3 -0
- package/dist/web/platform/src/deep-links.web.js +3 -0
- package/dist/web/platform/src/device.web.js +2 -0
- package/dist/web/platform/src/host-bridge.web.js +18 -0
- package/dist/web/platform/src/host-protocol.js +73 -0
- package/dist/web/platform/src/host-runtime.web.js +76 -0
- package/dist/web/platform/src/index.web.js +13 -0
- package/dist/web/platform/src/lifecycle.web.tsrx.js +3 -0
- package/dist/web/platform/src/locale.web.js +10 -0
- package/dist/web/platform/src/random.web.js +21 -0
- package/dist/web/platform/src/safe-area.web.tsrx.js +3 -0
- package/dist/web/platform/src/screen.web.tsrx.js +3 -0
- package/dist/web/platform/src/webauthn.web.js +2 -0
- package/dist/web/secure-storage/src/secure-storage.web.js +21 -0
- package/package.json +6 -4
- package/src/apple.macos.ts +1 -81
- package/src/base64.ts +25 -0
- package/src/hosted.ts +392 -0
- package/src/index.macos.ts +16 -0
- package/src/index.ts +16 -0
- package/src/index.web.ts +16 -0
- package/src/sha256.ts +118 -0
- package/src/types.ts +197 -0
- package/types/generated/.tsrx-typegen-manifest.json +3 -0
- package/types/generated/base64.d.ts +1 -0
- package/types/generated/hosted.d.ts +6 -0
- package/types/generated/index.d.ts +2 -1
- package/types/generated/index.web.d.ts +2 -1
- package/types/generated/sha256.d.ts +4 -0
- package/types/generated/types.d.ts +182 -0
- package/types/index.macos.d.ts +38 -0
- /package/dist/native/{AppleSignInButton.tsrx.js → auth/src/AppleSignInButton.tsrx.js} +0 -0
- /package/dist/native/{GoogleSignInButton.tsrx.js → auth/src/GoogleSignInButton.tsrx.js} +0 -0
- /package/dist/native/{apple.js → auth/src/apple.js} +0 -0
- /package/dist/native/{google.js → auth/src/google.js} +0 -0
- /package/dist/web/{AppleSignInButton.web.tsrx.js → auth/src/AppleSignInButton.web.tsrx.js} +0 -0
- /package/dist/web/{GoogleSignInButton.web.tsrx.js → auth/src/GoogleSignInButton.web.tsrx.js} +0 -0
- /package/dist/web/{apple.web.js → auth/src/apple.web.js} +0 -0
- /package/dist/web/{google.web.js → auth/src/google.web.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@nativescript/core";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Application } from "@nativescript/core";
|
|
2
|
+
//#region ../platform/src/random.ts
|
|
3
|
+
var iosReady = () => Application.ios != null && typeof SecRandomCopyBytes === "function" && typeof NSMutableData !== "undefined";
|
|
4
|
+
var androidReady = () => Application.android != null && typeof java !== "undefined" && typeof Array.create === "function";
|
|
5
|
+
var secureRandom;
|
|
6
|
+
function fillBytes(target) {
|
|
7
|
+
if (target.length === 0) return;
|
|
8
|
+
if (iosReady()) {
|
|
9
|
+
const data = NSMutableData.dataWithLength(target.length);
|
|
10
|
+
if (SecRandomCopyBytes(kSecRandomDefault, target.length, data.mutableBytes) !== 0) throw new Error("random: SecRandomCopyBytes failed");
|
|
11
|
+
target.set(new Uint8Array(interop.bufferFromData(data)));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (androidReady()) {
|
|
15
|
+
secureRandom ??= new java.security.SecureRandom();
|
|
16
|
+
const buffer = Array.create("byte", target.length);
|
|
17
|
+
secureRandom.nextBytes(buffer);
|
|
18
|
+
for (let i = 0; i < target.length; i++) target[i] = buffer[i];
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
throw new Error("random: no OS CSPRNG bound on this target");
|
|
22
|
+
}
|
|
23
|
+
var random = {
|
|
24
|
+
get supported() {
|
|
25
|
+
return iosReady() || androidReady();
|
|
26
|
+
},
|
|
27
|
+
fill(view) {
|
|
28
|
+
if (!ArrayBuffer.isView(view)) throw new TypeError("random.fill: expected an ArrayBufferView");
|
|
29
|
+
fillBytes(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
|
|
30
|
+
return view;
|
|
31
|
+
},
|
|
32
|
+
bytes(length) {
|
|
33
|
+
if (!Number.isInteger(length) || length < 0) throw new RangeError("random.bytes: length must be a non-negative integer");
|
|
34
|
+
return random.fill(new Uint8Array(length));
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
export { random };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@nativescript/core";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@nativescript/core";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SecureStorage } from "@nativescript/secure-storage";
|
|
2
|
+
//#region ../secure-storage/src/secure-storage.ts
|
|
3
|
+
var store = new SecureStorage();
|
|
4
|
+
var secureStorage = {
|
|
5
|
+
supported: true,
|
|
6
|
+
ensure: async () => "granted",
|
|
7
|
+
impl: {
|
|
8
|
+
get: (key) => store.get({ key }).then((v) => v ?? null),
|
|
9
|
+
set: (key, value) => store.set({
|
|
10
|
+
key,
|
|
11
|
+
value
|
|
12
|
+
}),
|
|
13
|
+
remove: (key) => store.remove({ key })
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { secureStorage };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/base64.ts
|
|
2
|
+
var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
3
|
+
function bytesToBase64Url(bytes) {
|
|
4
|
+
let out = "";
|
|
5
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
6
|
+
const a = bytes[i];
|
|
7
|
+
const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
|
|
8
|
+
const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
|
|
9
|
+
out += ALPHABET[a >> 2];
|
|
10
|
+
out += ALPHABET[(a & 3) << 4 | b >> 4];
|
|
11
|
+
if (i + 1 < bytes.length) out += ALPHABET[(b & 15) << 2 | c >> 6];
|
|
12
|
+
if (i + 2 < bytes.length) out += ALPHABET[c & 63];
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { bytesToBase64Url };
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { random } from "../../platform/src/random.web.js";
|
|
2
|
+
import { authSession } from "../../platform/src/auth-session.web.js";
|
|
3
|
+
import "../../platform/src/index.web.js";
|
|
4
|
+
import { secureStorage } from "../../secure-storage/src/secure-storage.web.js";
|
|
5
|
+
import { bytesToBase64Url } from "./base64.js";
|
|
6
|
+
import { sha256, utf8Bytes } from "./sha256.js";
|
|
7
|
+
//#region src/hosted.ts
|
|
8
|
+
var DEFAULT_STORAGE_KEY = "hosted-auth";
|
|
9
|
+
var REFRESH_SKEW_MS = 3e4;
|
|
10
|
+
function createHostedAuth(config) {
|
|
11
|
+
const apiOrigin = normalizeOrigin(config.apiOrigin);
|
|
12
|
+
const authorizePath = config.authorizePath ?? defaultAuthorizePath;
|
|
13
|
+
const storageKey = config.storageKey ?? DEFAULT_STORAGE_KEY;
|
|
14
|
+
const now = config.now ?? Date.now;
|
|
15
|
+
const transport = config.fetch ?? ((url, init) => {
|
|
16
|
+
const impl = globalThis.fetch;
|
|
17
|
+
if (!impl) return Promise.reject(/* @__PURE__ */ new Error("hostedAuth: fetch is unavailable on this target"));
|
|
18
|
+
return impl(url, init);
|
|
19
|
+
});
|
|
20
|
+
let credentials;
|
|
21
|
+
let refreshPromise = null;
|
|
22
|
+
function store() {
|
|
23
|
+
return config.storage ?? secureStorage.impl;
|
|
24
|
+
}
|
|
25
|
+
async function persist(creds) {
|
|
26
|
+
credentials = creds;
|
|
27
|
+
const storage = store();
|
|
28
|
+
if (!storage) return;
|
|
29
|
+
try {
|
|
30
|
+
if (creds) await storage.set(storageKey, JSON.stringify(creds));
|
|
31
|
+
else await storage.remove(storageKey);
|
|
32
|
+
} catch {}
|
|
33
|
+
}
|
|
34
|
+
async function load() {
|
|
35
|
+
if (credentials !== void 0) return credentials;
|
|
36
|
+
const storage = store();
|
|
37
|
+
if (!storage) {
|
|
38
|
+
credentials = null;
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const raw = await storage.get(storageKey);
|
|
43
|
+
const parsed = raw ? parseCredentials(raw) : null;
|
|
44
|
+
if (credentials === void 0) credentials = parsed;
|
|
45
|
+
if (!parsed && raw) await storage.remove(storageKey);
|
|
46
|
+
} catch {
|
|
47
|
+
credentials ??= null;
|
|
48
|
+
}
|
|
49
|
+
return credentials ?? null;
|
|
50
|
+
}
|
|
51
|
+
async function refresh() {
|
|
52
|
+
const creds = await load();
|
|
53
|
+
if (!creds || !config.flow.refresh) return null;
|
|
54
|
+
const next = await config.flow.refresh(creds, { fetch: transport });
|
|
55
|
+
if (!isCredentials(next)) {
|
|
56
|
+
await persist(null);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
await persist(next);
|
|
60
|
+
return next.token;
|
|
61
|
+
}
|
|
62
|
+
function refreshedAccessToken() {
|
|
63
|
+
refreshPromise ??= refresh().finally(() => {
|
|
64
|
+
refreshPromise = null;
|
|
65
|
+
});
|
|
66
|
+
return refreshPromise;
|
|
67
|
+
}
|
|
68
|
+
async function getAccessToken() {
|
|
69
|
+
const creds = await load();
|
|
70
|
+
if (!creds) return null;
|
|
71
|
+
if (creds.expiresAt - now() > REFRESH_SKEW_MS) return creds.token;
|
|
72
|
+
return refreshedAccessToken();
|
|
73
|
+
}
|
|
74
|
+
async function signIn() {
|
|
75
|
+
const session = config.authSession ?? {
|
|
76
|
+
supported: authSession.supported,
|
|
77
|
+
open: (url, options) => {
|
|
78
|
+
const impl = authSession.impl;
|
|
79
|
+
if (!impl) return Promise.resolve({
|
|
80
|
+
type: "error",
|
|
81
|
+
message: "hostedAuth: hosted sign-in is not supported on this target"
|
|
82
|
+
});
|
|
83
|
+
return impl.open(url, options);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
if (!session.supported || !random.supported) return {
|
|
87
|
+
status: "error",
|
|
88
|
+
message: "hostedAuth: hosted sign-in is not supported on this target"
|
|
89
|
+
};
|
|
90
|
+
const verifier = bytesToBase64Url(random.bytes(32));
|
|
91
|
+
const pkce = {
|
|
92
|
+
challenge: bytesToBase64Url(sha256(utf8Bytes(verifier))),
|
|
93
|
+
verifier
|
|
94
|
+
};
|
|
95
|
+
let attempt;
|
|
96
|
+
try {
|
|
97
|
+
attempt = await config.flow.begin({
|
|
98
|
+
fetch: transport,
|
|
99
|
+
pkce
|
|
100
|
+
});
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
status: "error",
|
|
104
|
+
message: errorMessage(error)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const result = await session.open(attempt.url, { callbackScheme: attempt.callbackScheme });
|
|
108
|
+
if (result.type === "cancel") return { status: "cancelled" };
|
|
109
|
+
if (result.type === "error") return {
|
|
110
|
+
status: "error",
|
|
111
|
+
message: result.message
|
|
112
|
+
};
|
|
113
|
+
if (attempt.state !== void 0 && queryParam(result.url, "state") !== attempt.state) return {
|
|
114
|
+
status: "error",
|
|
115
|
+
message: "hostedAuth: callback did not carry the expected state"
|
|
116
|
+
};
|
|
117
|
+
try {
|
|
118
|
+
const creds = await config.flow.complete(result.url, attempt, {
|
|
119
|
+
fetch: transport,
|
|
120
|
+
pkce
|
|
121
|
+
});
|
|
122
|
+
if (!isCredentials(creds)) return {
|
|
123
|
+
status: "error",
|
|
124
|
+
message: "hostedAuth: sign-in did not produce credentials"
|
|
125
|
+
};
|
|
126
|
+
await persist(creds);
|
|
127
|
+
return { status: "success" };
|
|
128
|
+
} catch (error) {
|
|
129
|
+
return {
|
|
130
|
+
status: "error",
|
|
131
|
+
message: errorMessage(error)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function fetchWithAuth(url, init) {
|
|
136
|
+
const pathname = apiPath(url, apiOrigin);
|
|
137
|
+
if (pathname === null || !authorizePath(pathname)) return transport(url, init);
|
|
138
|
+
const target = url.startsWith("/") ? `${apiOrigin}${url}` : url;
|
|
139
|
+
const token = await getAccessToken();
|
|
140
|
+
const response = await transport(target, token === null ? init : withBearer(init, token));
|
|
141
|
+
if (!isInvalidAccessTokenChallenge(response.status, response.headers)) return response;
|
|
142
|
+
const refreshed = await refreshedAccessToken();
|
|
143
|
+
if (refreshed === null) return response;
|
|
144
|
+
return transport(target, withBearer(init, refreshed));
|
|
145
|
+
}
|
|
146
|
+
async function signOut() {
|
|
147
|
+
const creds = await load();
|
|
148
|
+
await persist(null);
|
|
149
|
+
if (!creds || !config.flow.revoke) return;
|
|
150
|
+
try {
|
|
151
|
+
await config.flow.revoke(creds, { fetch: transport });
|
|
152
|
+
} catch {}
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
get supported() {
|
|
156
|
+
return (config.authSession?.supported ?? authSession.supported) && random.supported;
|
|
157
|
+
},
|
|
158
|
+
restore: async () => await load() ? "authenticated" : "unauthenticated",
|
|
159
|
+
signIn,
|
|
160
|
+
getAccessToken,
|
|
161
|
+
fetch: fetchWithAuth,
|
|
162
|
+
signOut
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function normalizeOrigin(value) {
|
|
166
|
+
const trimmed = value.trim().replace(/\/+$/u, "");
|
|
167
|
+
if (!/^https?:\/\/[^\s/?#]+$/u.test(trimmed)) throw new TypeError(`hostedAuth: apiOrigin must be an HTTP(S) origin without path or parameters, got ${JSON.stringify(value)}`);
|
|
168
|
+
return trimmed;
|
|
169
|
+
}
|
|
170
|
+
/** `POST` a JSON body through the flow's transport. */
|
|
171
|
+
function postJson(transport, url, body) {
|
|
172
|
+
return transport(url, {
|
|
173
|
+
body: JSON.stringify(body),
|
|
174
|
+
headers: { "content-type": "application/json" },
|
|
175
|
+
method: "POST"
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/** `?name=value` extraction without URLSearchParams (not in the native program). */
|
|
179
|
+
function queryParam(url, name) {
|
|
180
|
+
const start = url.indexOf("?");
|
|
181
|
+
if (start === -1) return null;
|
|
182
|
+
const query = url.slice(start + 1).split("#", 1)[0];
|
|
183
|
+
for (const pair of query.split("&")) {
|
|
184
|
+
const eq = pair.indexOf("=");
|
|
185
|
+
if ((eq === -1 ? pair : pair.slice(0, eq)) === name) return eq === -1 ? "" : decodeURIComponent(pair.slice(eq + 1).replaceAll("+", " "));
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
function isCredentials(value) {
|
|
190
|
+
const creds = value;
|
|
191
|
+
return !!creds && typeof creds.token === "string" && typeof creds.expiresAt === "number" && typeof creds.sessionToken === "string";
|
|
192
|
+
}
|
|
193
|
+
function parseCredentials(raw) {
|
|
194
|
+
try {
|
|
195
|
+
const parsed = JSON.parse(raw);
|
|
196
|
+
if (isCredentials(parsed)) return {
|
|
197
|
+
expiresAt: parsed.expiresAt,
|
|
198
|
+
sessionToken: parsed.sessionToken,
|
|
199
|
+
token: parsed.token
|
|
200
|
+
};
|
|
201
|
+
} catch {}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Pathname of `url` when it belongs to `apiOrigin` — `null` for other
|
|
206
|
+
* origins. Relative (`/path`) and origin-prefixed inputs both resolve.
|
|
207
|
+
*/
|
|
208
|
+
function apiPath(url, apiOrigin) {
|
|
209
|
+
if (url.startsWith("//")) return null;
|
|
210
|
+
let path;
|
|
211
|
+
if (url.startsWith("/")) path = url;
|
|
212
|
+
else if (url.startsWith(apiOrigin + "/") || url === apiOrigin) path = url.slice(apiOrigin.length) || "/";
|
|
213
|
+
else return null;
|
|
214
|
+
const end = path.search(/[?#]/u);
|
|
215
|
+
return end === -1 ? path : path.slice(0, end);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Default `authorizePath` — every same-origin path under `/api/` except the
|
|
219
|
+
* `/api/auth` mount hosted backends reserve for auth endpoints.
|
|
220
|
+
*/
|
|
221
|
+
function defaultAuthorizePath(pathname) {
|
|
222
|
+
return pathname.startsWith("/api/") && !(pathname === "/api/auth" || pathname.startsWith("/api/auth/"));
|
|
223
|
+
}
|
|
224
|
+
function withBearer(init, token) {
|
|
225
|
+
const headers = {};
|
|
226
|
+
const incoming = init?.headers;
|
|
227
|
+
if (incoming) {
|
|
228
|
+
if (Symbol.iterator in incoming) for (const [name, value] of incoming) headers[name.toLowerCase()] = value;
|
|
229
|
+
else for (const name of Object.keys(incoming)) headers[name.toLowerCase()] = incoming[name];
|
|
230
|
+
}
|
|
231
|
+
headers.authorization = `Bearer ${token}`;
|
|
232
|
+
return {
|
|
233
|
+
...init,
|
|
234
|
+
headers
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* RFC 6750 `401 + WWW-Authenticate: Bearer error="invalid_token"` — the
|
|
239
|
+
* challenge that distinguishes a dead access token from an ordinary
|
|
240
|
+
* authorization failure.
|
|
241
|
+
*/
|
|
242
|
+
function isInvalidAccessTokenChallenge(status, headers) {
|
|
243
|
+
if (status !== 401) return false;
|
|
244
|
+
const challenge = headers.get("www-authenticate");
|
|
245
|
+
return !!challenge && /error\s*=\s*"invalid_token"/iu.test(challenge);
|
|
246
|
+
}
|
|
247
|
+
function errorMessage(error) {
|
|
248
|
+
return error instanceof Error ? error.message : "hostedAuth: the hosted ceremony failed";
|
|
249
|
+
}
|
|
250
|
+
//#endregion
|
|
251
|
+
export { createHostedAuth, postJson, queryParam };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
//#region src/sha256.ts
|
|
2
|
+
function utf8Bytes(input) {
|
|
3
|
+
const bytes = [];
|
|
4
|
+
for (let i = 0; i < input.length; i++) {
|
|
5
|
+
let cp = input.charCodeAt(i);
|
|
6
|
+
if (cp >= 55296 && cp <= 56319 && i + 1 < input.length) {
|
|
7
|
+
const low = input.charCodeAt(i + 1);
|
|
8
|
+
if (low >= 56320 && low <= 57343) {
|
|
9
|
+
cp = 65536 + (cp - 55296 << 10) + (low - 56320);
|
|
10
|
+
i++;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (cp < 128) bytes.push(cp);
|
|
14
|
+
else if (cp < 2048) bytes.push(192 | cp >> 6, 128 | cp & 63);
|
|
15
|
+
else if (cp < 65536) bytes.push(224 | cp >> 12, 128 | cp >> 6 & 63, 128 | cp & 63);
|
|
16
|
+
else bytes.push(240 | cp >> 18, 128 | cp >> 12 & 63, 128 | cp >> 6 & 63, 128 | cp & 63);
|
|
17
|
+
}
|
|
18
|
+
return new Uint8Array(bytes);
|
|
19
|
+
}
|
|
20
|
+
function sha256(bytes) {
|
|
21
|
+
const K = new Uint32Array([
|
|
22
|
+
1116352408,
|
|
23
|
+
1899447441,
|
|
24
|
+
3049323471,
|
|
25
|
+
3921009573,
|
|
26
|
+
961987163,
|
|
27
|
+
1508970993,
|
|
28
|
+
2453635748,
|
|
29
|
+
2870763221,
|
|
30
|
+
3624381080,
|
|
31
|
+
310598401,
|
|
32
|
+
607225278,
|
|
33
|
+
1426881987,
|
|
34
|
+
1925078388,
|
|
35
|
+
2162078206,
|
|
36
|
+
2614888103,
|
|
37
|
+
3248222580,
|
|
38
|
+
3835390401,
|
|
39
|
+
4022224774,
|
|
40
|
+
264347078,
|
|
41
|
+
604807628,
|
|
42
|
+
770255983,
|
|
43
|
+
1249150122,
|
|
44
|
+
1555081692,
|
|
45
|
+
1996064986,
|
|
46
|
+
2554220882,
|
|
47
|
+
2821834349,
|
|
48
|
+
2952996808,
|
|
49
|
+
3210313671,
|
|
50
|
+
3336571891,
|
|
51
|
+
3584528711,
|
|
52
|
+
113926993,
|
|
53
|
+
338241895,
|
|
54
|
+
666307205,
|
|
55
|
+
773529912,
|
|
56
|
+
1294757372,
|
|
57
|
+
1396182291,
|
|
58
|
+
1695183700,
|
|
59
|
+
1986661051,
|
|
60
|
+
2177026350,
|
|
61
|
+
2456956037,
|
|
62
|
+
2730485921,
|
|
63
|
+
2820302411,
|
|
64
|
+
3259730800,
|
|
65
|
+
3345764771,
|
|
66
|
+
3516065817,
|
|
67
|
+
3600352804,
|
|
68
|
+
4094571909,
|
|
69
|
+
275423344,
|
|
70
|
+
430227734,
|
|
71
|
+
506948616,
|
|
72
|
+
659060556,
|
|
73
|
+
883997877,
|
|
74
|
+
958139571,
|
|
75
|
+
1322822218,
|
|
76
|
+
1537002063,
|
|
77
|
+
1747873779,
|
|
78
|
+
1955562222,
|
|
79
|
+
2024104815,
|
|
80
|
+
2227730452,
|
|
81
|
+
2361852424,
|
|
82
|
+
2428436474,
|
|
83
|
+
2756734187,
|
|
84
|
+
3204031479,
|
|
85
|
+
3329325298
|
|
86
|
+
]);
|
|
87
|
+
const H = new Uint32Array([
|
|
88
|
+
1779033703,
|
|
89
|
+
3144134277,
|
|
90
|
+
1013904242,
|
|
91
|
+
2773480762,
|
|
92
|
+
1359893119,
|
|
93
|
+
2600822924,
|
|
94
|
+
528734635,
|
|
95
|
+
1541459225
|
|
96
|
+
]);
|
|
97
|
+
const bitLen = bytes.length * 8;
|
|
98
|
+
const padded = new Uint8Array(bytes.length + 9 + 63 & -64);
|
|
99
|
+
padded.set(bytes);
|
|
100
|
+
padded[bytes.length] = 128;
|
|
101
|
+
const dv = new DataView(padded.buffer);
|
|
102
|
+
dv.setUint32(padded.length - 8, Math.floor(bitLen / 4294967296));
|
|
103
|
+
dv.setUint32(padded.length - 4, bitLen >>> 0);
|
|
104
|
+
const w = /* @__PURE__ */ new Uint32Array(64);
|
|
105
|
+
for (let block = 0; block < padded.length; block += 64) {
|
|
106
|
+
for (let t = 0; t < 16; t++) w[t] = dv.getUint32(block + t * 4);
|
|
107
|
+
for (let t = 16; t < 64; t++) {
|
|
108
|
+
const s0 = (w[t - 15] >>> 7 | w[t - 15] << 25) ^ (w[t - 15] >>> 18 | w[t - 15] << 14) ^ w[t - 15] >>> 3;
|
|
109
|
+
const s1 = (w[t - 2] >>> 17 | w[t - 2] << 15) ^ (w[t - 2] >>> 19 | w[t - 2] << 13) ^ w[t - 2] >>> 10;
|
|
110
|
+
w[t] = w[t - 16] + s0 + w[t - 7] + s1 >>> 0;
|
|
111
|
+
}
|
|
112
|
+
let [a, b, c, d, e, f, g, h] = H;
|
|
113
|
+
for (let t = 0; t < 64; t++) {
|
|
114
|
+
const S1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
|
|
115
|
+
const t1 = h + S1 + (e & f ^ ~e & g) + K[t] + w[t] >>> 0;
|
|
116
|
+
const t2 = ((a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10)) + (a & b ^ a & c ^ b & c) >>> 0;
|
|
117
|
+
h = g;
|
|
118
|
+
g = f;
|
|
119
|
+
f = e;
|
|
120
|
+
e = d + t1 >>> 0;
|
|
121
|
+
d = c;
|
|
122
|
+
c = b;
|
|
123
|
+
b = a;
|
|
124
|
+
a = t1 + t2 >>> 0;
|
|
125
|
+
}
|
|
126
|
+
H[0] = H[0] + a >>> 0;
|
|
127
|
+
H[1] = H[1] + b >>> 0;
|
|
128
|
+
H[2] = H[2] + c >>> 0;
|
|
129
|
+
H[3] = H[3] + d >>> 0;
|
|
130
|
+
H[4] = H[4] + e >>> 0;
|
|
131
|
+
H[5] = H[5] + f >>> 0;
|
|
132
|
+
H[6] = H[6] + g >>> 0;
|
|
133
|
+
H[7] = H[7] + h >>> 0;
|
|
134
|
+
}
|
|
135
|
+
const digest = /* @__PURE__ */ new Uint8Array(32);
|
|
136
|
+
const out = new DataView(digest.buffer);
|
|
137
|
+
for (let i = 0; i < 8; i++) out.setUint32(i * 4, H[i]);
|
|
138
|
+
return digest;
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
export { sha256, utf8Bytes };
|
package/dist/web/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { appleAuth } from "./apple.web.js";
|
|
2
|
-
import { googleAuth } from "./google.web.js";
|
|
3
|
-
import { AppleSignInButton } from "./AppleSignInButton.web.tsrx.js";
|
|
4
|
-
import { GoogleSignInButton } from "./GoogleSignInButton.web.tsrx.js";
|
|
5
|
-
|
|
1
|
+
import { appleAuth } from "./auth/src/apple.web.js";
|
|
2
|
+
import { googleAuth } from "./auth/src/google.web.js";
|
|
3
|
+
import { AppleSignInButton } from "./auth/src/AppleSignInButton.web.tsrx.js";
|
|
4
|
+
import { GoogleSignInButton } from "./auth/src/GoogleSignInButton.web.tsrx.js";
|
|
5
|
+
import { createHostedAuth, postJson, queryParam } from "./auth/src/hosted.js";
|
|
6
|
+
export { AppleSignInButton, GoogleSignInButton, appleAuth, createHostedAuth, googleAuth, postJson, queryParam };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { hookSlots } from "octane";
|
|
2
|
+
import { enableNativeReadCollection } from "octane/internal/client";
|
|
3
|
+
import "octane/signals/client";
|
|
4
|
+
//#region ../platform/src/breakpoints.web.tsrx
|
|
5
|
+
enableNativeReadCollection(1);
|
|
6
|
+
/* @__PURE__ */ hookSlots(2) + 1;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region ../platform/src/host-bridge.web.ts
|
|
2
|
+
/** Return the native message channel when this page is hosted by a desktop app. */
|
|
3
|
+
function createWebKitTransport() {
|
|
4
|
+
if (typeof window === "undefined") return null;
|
|
5
|
+
const handler = window.webkit?.messageHandlers?.xplat;
|
|
6
|
+
const host = window.__xplatHostTransport;
|
|
7
|
+
if (!handler || !host) return null;
|
|
8
|
+
return {
|
|
9
|
+
postMessage(message) {
|
|
10
|
+
handler.postMessage(message);
|
|
11
|
+
},
|
|
12
|
+
listen(listener) {
|
|
13
|
+
return host.listen(listener);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { createWebKitTransport };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region ../platform/src/host-protocol.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create the webview-side client. Host methods are typed at compile time; this
|
|
4
|
+
* deliberately does not add runtime schema validation.
|
|
5
|
+
*/
|
|
6
|
+
function createHostClient(transport) {
|
|
7
|
+
const pending = /* @__PURE__ */ new Map();
|
|
8
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
9
|
+
let nextId = 0;
|
|
10
|
+
let disposed = false;
|
|
11
|
+
const removeListener = transport.listen((message) => {
|
|
12
|
+
const packet = JSON.parse(message);
|
|
13
|
+
if (packet.type === "reply") {
|
|
14
|
+
const task = pending.get(packet.id);
|
|
15
|
+
if (!task) return;
|
|
16
|
+
pending.delete(packet.id);
|
|
17
|
+
if (packet.ok) task.resolve(packet.value);
|
|
18
|
+
else task.reject(new Error(packet.error));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
for (const listener of listeners.get(packet.name) ?? []) listener(packet.payload);
|
|
22
|
+
});
|
|
23
|
+
const request = (value) => {
|
|
24
|
+
if (disposed) return Promise.reject(/* @__PURE__ */ new Error("desktop host client is disposed"));
|
|
25
|
+
const id = ++nextId;
|
|
26
|
+
const promise = new Promise((resolve, reject) => pending.set(id, {
|
|
27
|
+
resolve,
|
|
28
|
+
reject
|
|
29
|
+
}));
|
|
30
|
+
try {
|
|
31
|
+
transport.postMessage(JSON.stringify({
|
|
32
|
+
...value,
|
|
33
|
+
id
|
|
34
|
+
}));
|
|
35
|
+
} catch (error) {
|
|
36
|
+
const task = pending.get(id);
|
|
37
|
+
pending.delete(id);
|
|
38
|
+
task?.reject(error instanceof Error ? error : new Error(String(error)));
|
|
39
|
+
}
|
|
40
|
+
return promise;
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
call: ((service, method, ...args) => request({
|
|
44
|
+
type: "call",
|
|
45
|
+
service,
|
|
46
|
+
method,
|
|
47
|
+
args
|
|
48
|
+
})),
|
|
49
|
+
capabilities() {
|
|
50
|
+
return request({ type: "capabilities" });
|
|
51
|
+
},
|
|
52
|
+
on(name, listener) {
|
|
53
|
+
const eventListeners = listeners.get(name) ?? /* @__PURE__ */ new Set();
|
|
54
|
+
const receive = listener;
|
|
55
|
+
eventListeners.add(receive);
|
|
56
|
+
listeners.set(name, eventListeners);
|
|
57
|
+
return () => {
|
|
58
|
+
eventListeners.delete(receive);
|
|
59
|
+
if (!eventListeners.size) listeners.delete(name);
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
dispose() {
|
|
63
|
+
if (disposed) return;
|
|
64
|
+
disposed = true;
|
|
65
|
+
removeListener();
|
|
66
|
+
listeners.clear();
|
|
67
|
+
for (const task of pending.values()) task.reject(/* @__PURE__ */ new Error("desktop host client is disposed"));
|
|
68
|
+
pending.clear();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { createHostClient };
|