@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,76 @@
|
|
|
1
|
+
import { createWebKitTransport } from "./host-bridge.web.js";
|
|
2
|
+
import { createHostClient } from "./host-protocol.js";
|
|
3
|
+
//#region ../platform/src/host-runtime.web.ts
|
|
4
|
+
var client;
|
|
5
|
+
var capabilityTable;
|
|
6
|
+
/** Return the native service client when this page is inside a desktop webview. */
|
|
7
|
+
function desktopHostClient() {
|
|
8
|
+
if (client !== void 0) return client;
|
|
9
|
+
const transport = createWebKitTransport();
|
|
10
|
+
client = transport ? createHostClient(transport) : null;
|
|
11
|
+
return client;
|
|
12
|
+
}
|
|
13
|
+
/** Read values installed before the document's application scripts execute. */
|
|
14
|
+
function desktopHostBootstrap() {
|
|
15
|
+
if (typeof window === "undefined") return null;
|
|
16
|
+
return window.__xplatHostSnapshot ?? null;
|
|
17
|
+
}
|
|
18
|
+
function desktopHostSupports(service, method) {
|
|
19
|
+
const host = desktopHostClient();
|
|
20
|
+
if (!host) return Promise.resolve(false);
|
|
21
|
+
capabilityTable ??= host.capabilities().catch(() => ({}));
|
|
22
|
+
return capabilityTable.then((capabilities) => capabilities[service]?.includes(method) ?? false);
|
|
23
|
+
}
|
|
24
|
+
/** Typed desktop service facade; null outside a supported native webview. */
|
|
25
|
+
function desktopHost() {
|
|
26
|
+
const host = desktopHostClient();
|
|
27
|
+
if (!host) return null;
|
|
28
|
+
return {
|
|
29
|
+
app: {
|
|
30
|
+
getInfo: () => host.call("app", "getInfo"),
|
|
31
|
+
getState: () => host.call("app", "getState"),
|
|
32
|
+
getWindowSize: () => host.call("app", "getWindowSize"),
|
|
33
|
+
consumeInitialUrl: () => host.call("app", "consumeInitialUrl")
|
|
34
|
+
},
|
|
35
|
+
clipboard: {
|
|
36
|
+
read: () => host.call("clipboard", "read"),
|
|
37
|
+
write: (value) => host.call("clipboard", "write", value)
|
|
38
|
+
},
|
|
39
|
+
files: {
|
|
40
|
+
pick: (accept, options) => host.call("files", "pick", accept, options),
|
|
41
|
+
readText: (uri) => host.call("files", "readText", uri),
|
|
42
|
+
writeText: (name, text) => host.call("files", "writeText", name, text)
|
|
43
|
+
},
|
|
44
|
+
notifications: {
|
|
45
|
+
ensure: () => host.call("notifications", "ensure"),
|
|
46
|
+
notify: (title, body) => host.call("notifications", "notify", title, body)
|
|
47
|
+
},
|
|
48
|
+
secureStorage: {
|
|
49
|
+
get: (key) => host.call("secureStorage", "get", key),
|
|
50
|
+
set: (key, value) => host.call("secureStorage", "set", key, value),
|
|
51
|
+
remove: (key) => host.call("secureStorage", "remove", key)
|
|
52
|
+
},
|
|
53
|
+
appearance: { get: () => host.call("appearance", "get") },
|
|
54
|
+
windows: {
|
|
55
|
+
open: (options) => host.call("windows", "open", options),
|
|
56
|
+
close: (id) => host.call("windows", "close", id),
|
|
57
|
+
setTitle: (id, title) => host.call("windows", "setTitle", id, title)
|
|
58
|
+
},
|
|
59
|
+
system: {
|
|
60
|
+
openUrl: (url) => host.call("system", "openUrl", url),
|
|
61
|
+
openPath: (path) => host.call("system", "openPath", path),
|
|
62
|
+
shareContent: (input) => host.call("system", "shareContent", input)
|
|
63
|
+
},
|
|
64
|
+
storage: {
|
|
65
|
+
get: (key) => host.call("storage", "get", key),
|
|
66
|
+
set: (key, value) => host.call("storage", "set", key, value),
|
|
67
|
+
remove: (key) => host.call("storage", "remove", key)
|
|
68
|
+
},
|
|
69
|
+
capabilities: () => host.capabilities(),
|
|
70
|
+
supports: desktopHostSupports,
|
|
71
|
+
on: (name, listener) => host.on(name, listener),
|
|
72
|
+
dispose: () => host.dispose()
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { desktopHost, desktopHostBootstrap, desktopHostClient, desktopHostSupports };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import "./device.web.js";
|
|
2
|
+
import "./app-info.web.js";
|
|
3
|
+
import "./clipboard.web.js";
|
|
4
|
+
import "./locale.web.js";
|
|
5
|
+
import "./webauthn.web.js";
|
|
6
|
+
import { random } from "./random.web.js";
|
|
7
|
+
import { authSession } from "./auth-session.web.js";
|
|
8
|
+
import "./deep-links.web.js";
|
|
9
|
+
import "./lifecycle.web.tsrx.js";
|
|
10
|
+
import "./safe-area.web.tsrx.js";
|
|
11
|
+
import "./screen.web.tsrx.js";
|
|
12
|
+
import "./breakpoints.web.tsrx.js";
|
|
13
|
+
export { authSession, random };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region ../platform/src/random.web.ts
|
|
2
|
+
var source = () => typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function" ? crypto : null;
|
|
3
|
+
var random = {
|
|
4
|
+
get supported() {
|
|
5
|
+
return source() !== null;
|
|
6
|
+
},
|
|
7
|
+
fill(view) {
|
|
8
|
+
if (!ArrayBuffer.isView(view)) throw new TypeError("random.fill: expected an ArrayBufferView");
|
|
9
|
+
const crypto = source();
|
|
10
|
+
if (!crypto) throw new Error("random: crypto.getRandomValues is unavailable");
|
|
11
|
+
const target = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
|
|
12
|
+
for (let offset = 0; offset < target.length; offset += 65536) crypto.getRandomValues(target.subarray(offset, offset + 65536));
|
|
13
|
+
return view;
|
|
14
|
+
},
|
|
15
|
+
bytes(length) {
|
|
16
|
+
if (!Number.isInteger(length) || length < 0) throw new RangeError("random.bytes: length must be a non-negative integer");
|
|
17
|
+
return random.fill(new Uint8Array(length));
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { random };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { desktopHost } from "../../platform/src/host-runtime.web.js";
|
|
2
|
+
//#region ../secure-storage/src/secure-storage.web.ts
|
|
3
|
+
var hostStore = {
|
|
4
|
+
get: (key) => desktopHost()?.secureStorage.get(key) ?? Promise.resolve(null),
|
|
5
|
+
set: (key, value) => desktopHost()?.secureStorage.set(key, value) ?? Promise.resolve(false),
|
|
6
|
+
remove: (key) => desktopHost()?.secureStorage.remove(key) ?? Promise.resolve(false)
|
|
7
|
+
};
|
|
8
|
+
var secureStorage = {
|
|
9
|
+
get supported() {
|
|
10
|
+
return desktopHost() !== null;
|
|
11
|
+
},
|
|
12
|
+
async ensure() {
|
|
13
|
+
const host = desktopHost();
|
|
14
|
+
return host && await host.supports("secureStorage", "get") ? "granted" : "unsupported";
|
|
15
|
+
},
|
|
16
|
+
get impl() {
|
|
17
|
+
return desktopHost() ? hostStore : null;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { secureStorage };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octane-xplat/auth",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Sign in with Apple + Google Sign-In for Octane xplat — native SDKs on iOS/Android, platform web SDKs in the browser",
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"description": "Sign in with Apple + Google Sign-In + hosted-auth sessions for Octane xplat — native SDKs on iOS/Android, platform web SDKs in the browser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"android",
|
|
7
7
|
"apple",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"nativescript",
|
|
13
13
|
"oauth",
|
|
14
14
|
"octane",
|
|
15
|
+
"pkce",
|
|
15
16
|
"sign-in",
|
|
16
17
|
"web",
|
|
17
18
|
"xplat"
|
|
@@ -53,12 +54,13 @@
|
|
|
53
54
|
"dependencies": {
|
|
54
55
|
"@nativescript/apple-sign-in": "2.0.0",
|
|
55
56
|
"@nativescript/google-signin": "2.1.1",
|
|
56
|
-
"@octane-xplat/platform": "0.
|
|
57
|
+
"@octane-xplat/platform": "0.11.0",
|
|
58
|
+
"@octane-xplat/secure-storage": "0.11.0"
|
|
57
59
|
},
|
|
58
60
|
"devDependencies": {
|
|
59
61
|
"@nativescript-community/octane": "0.2.4",
|
|
60
62
|
"@nativescript/core": "9.1.2",
|
|
61
|
-
"@octane-xplat/macos-renderer": "0.
|
|
63
|
+
"@octane-xplat/macos-renderer": "0.11.0",
|
|
62
64
|
"@octanejs/vite-plugin": "0.1.61",
|
|
63
65
|
"@tsrx/typescript-plugin": "0.4.11",
|
|
64
66
|
"octane": "0.6.3",
|
package/src/apple.macos.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// available since macOS 10.15). The `com.apple.developer.applesignin`
|
|
4
4
|
// entitlement must sit on the packaged app for the sheet to present;
|
|
5
5
|
// hosts without it still load the framework and surface the OS error.
|
|
6
|
+
import { sha256Hex } from './sha256'
|
|
6
7
|
import type {
|
|
7
8
|
AppleAuth,
|
|
8
9
|
AppleAuthConfig,
|
|
@@ -46,87 +47,6 @@ function isCancel(error: unknown): boolean {
|
|
|
46
47
|
)
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
function utf8Bytes(input: string): Uint8Array {
|
|
50
|
-
const data = NSString.stringWithString(input).dataUsingEncoding(4 /* NSUTF8StringEncoding */)
|
|
51
|
-
return new Uint8Array(interop.bufferFromData(data))
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// FIPS 180-4 — the request nonce must be the hex SHA-256 of the app's nonce
|
|
55
|
-
// (same transform the iOS plugin applies via CommonCrypto, which has no
|
|
56
|
-
// node-api metadata). Kept local to stay dependency-free.
|
|
57
|
-
function sha256Hex(input: string): string {
|
|
58
|
-
const K = new Uint32Array([
|
|
59
|
-
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
60
|
-
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
61
|
-
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
62
|
-
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
63
|
-
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
64
|
-
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
65
|
-
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
66
|
-
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
67
|
-
])
|
|
68
|
-
|
|
69
|
-
const H = new Uint32Array([
|
|
70
|
-
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
71
|
-
])
|
|
72
|
-
|
|
73
|
-
const bytes = utf8Bytes(input)
|
|
74
|
-
const bitLen = bytes.length * 8
|
|
75
|
-
const padded = new Uint8Array((bytes.length + 9 + 63) & ~63)
|
|
76
|
-
padded.set(bytes)
|
|
77
|
-
padded[bytes.length] = 0x80
|
|
78
|
-
const dv = new DataView(padded.buffer)
|
|
79
|
-
dv.setUint32(padded.length - 8, Math.floor(bitLen / 0x100000000))
|
|
80
|
-
dv.setUint32(padded.length - 4, bitLen >>> 0)
|
|
81
|
-
const w = new Uint32Array(64)
|
|
82
|
-
for (let block = 0; block < padded.length; block += 64) {
|
|
83
|
-
for (let t = 0; t < 16; t++) {
|
|
84
|
-
w[t] = dv.getUint32(block + t * 4)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
for (let t = 16; t < 64; t++) {
|
|
88
|
-
const s0 =
|
|
89
|
-
((w[t - 15] >>> 7) | (w[t - 15] << 25)) ^
|
|
90
|
-
((w[t - 15] >>> 18) | (w[t - 15] << 14)) ^
|
|
91
|
-
(w[t - 15] >>> 3)
|
|
92
|
-
|
|
93
|
-
const s1 =
|
|
94
|
-
((w[t - 2] >>> 17) | (w[t - 2] << 15)) ^
|
|
95
|
-
((w[t - 2] >>> 19) | (w[t - 2] << 13)) ^
|
|
96
|
-
(w[t - 2] >>> 10)
|
|
97
|
-
|
|
98
|
-
w[t] = (w[t - 16] + s0 + w[t - 7] + s1) >>> 0
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
let [a, b, c, d, e, f, g, h] = H
|
|
102
|
-
for (let t = 0; t < 64; t++) {
|
|
103
|
-
const S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7))
|
|
104
|
-
const t1 = (h + S1 + ((e & f) ^ (~e & g)) + K[t] + w[t]) >>> 0
|
|
105
|
-
const S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10))
|
|
106
|
-
const t2 = (S0 + ((a & b) ^ (a & c) ^ (b & c))) >>> 0
|
|
107
|
-
h = g
|
|
108
|
-
g = f
|
|
109
|
-
f = e
|
|
110
|
-
e = (d + t1) >>> 0
|
|
111
|
-
d = c
|
|
112
|
-
c = b
|
|
113
|
-
b = a
|
|
114
|
-
a = (t1 + t2) >>> 0
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
H[0] = (H[0] + a) >>> 0
|
|
118
|
-
H[1] = (H[1] + b) >>> 0
|
|
119
|
-
H[2] = (H[2] + c) >>> 0
|
|
120
|
-
H[3] = (H[3] + d) >>> 0
|
|
121
|
-
H[4] = (H[4] + e) >>> 0
|
|
122
|
-
H[5] = (H[5] + f) >>> 0
|
|
123
|
-
H[6] = (H[6] + g) >>> 0
|
|
124
|
-
H[7] = (H[7] + h) >>> 0
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return [...H].map((x) => x.toString(16).padStart(8, '0')).join('')
|
|
128
|
-
}
|
|
129
|
-
|
|
130
50
|
function toCredential(credential: any): AuthCredential {
|
|
131
51
|
const tokenData = credential.valueForKey('identityToken')
|
|
132
52
|
const codeData = credential.valueForKey('authorizationCode')
|
package/src/base64.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Unpadded base64url (RFC 4648 §5) — the encoding PKCE and hosted-auth
|
|
2
|
+
// wire formats use. `btoa` is not declared on every target's typecheck,
|
|
3
|
+
// so encode by hand.
|
|
4
|
+
|
|
5
|
+
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
|
|
6
|
+
|
|
7
|
+
export function bytesToBase64Url(bytes: Uint8Array): string {
|
|
8
|
+
let out = ''
|
|
9
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
10
|
+
const a = bytes[i]
|
|
11
|
+
const b = i + 1 < bytes.length ? bytes[i + 1] : 0
|
|
12
|
+
const c = i + 2 < bytes.length ? bytes[i + 2] : 0
|
|
13
|
+
out += ALPHABET[a >> 2]
|
|
14
|
+
out += ALPHABET[((a & 0x03) << 4) | (b >> 4)]
|
|
15
|
+
if (i + 1 < bytes.length) {
|
|
16
|
+
out += ALPHABET[((b & 0x0f) << 2) | (c >> 6)]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (i + 2 < bytes.length) {
|
|
20
|
+
out += ALPHABET[c & 0x3f]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return out
|
|
25
|
+
}
|