@eazo/sdk 0.4.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/PROTOCOL.md +134 -0
- package/README.md +163 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/auth-primitive/EazoAuthClient.d.ts +35 -0
- package/dist/internal/auth-primitive/EazoAuthClient.d.ts.map +1 -0
- package/dist/internal/auth-primitive/EazoAuthClient.js +107 -0
- package/dist/internal/auth-primitive/EazoAuthClient.js.map +1 -0
- package/dist/internal/auth-primitive/EazoAuthServer.d.ts +18 -0
- package/dist/internal/auth-primitive/EazoAuthServer.d.ts.map +1 -0
- package/dist/internal/auth-primitive/EazoAuthServer.js +37 -0
- package/dist/internal/auth-primitive/EazoAuthServer.js.map +1 -0
- package/dist/internal/auth-primitive/decrypt.d.ts +12 -0
- package/dist/internal/auth-primitive/decrypt.d.ts.map +1 -0
- package/dist/internal/auth-primitive/decrypt.js +89 -0
- package/dist/internal/auth-primitive/decrypt.js.map +1 -0
- package/dist/internal/auth-primitive/index.d.ts +5 -0
- package/dist/internal/auth-primitive/index.d.ts.map +1 -0
- package/dist/internal/auth-primitive/index.js +13 -0
- package/dist/internal/auth-primitive/index.js.map +1 -0
- package/dist/internal/auth-primitive/types.d.ts +61 -0
- package/dist/internal/auth-primitive/types.d.ts.map +1 -0
- package/dist/internal/auth-primitive/types.js +6 -0
- package/dist/internal/auth-primitive/types.js.map +1 -0
- package/dist/internal/bootstrap.d.ts +16 -0
- package/dist/internal/bootstrap.d.ts.map +1 -0
- package/dist/internal/bootstrap.js +81 -0
- package/dist/internal/bootstrap.js.map +1 -0
- package/dist/internal/bridge/client.d.ts +40 -0
- package/dist/internal/bridge/client.d.ts.map +1 -0
- package/dist/internal/bridge/client.js +160 -0
- package/dist/internal/bridge/client.js.map +1 -0
- package/dist/internal/bridge/protocol.d.ts +61 -0
- package/dist/internal/bridge/protocol.d.ts.map +1 -0
- package/dist/internal/bridge/protocol.js +38 -0
- package/dist/internal/bridge/protocol.js.map +1 -0
- package/dist/internal/bridge/transport.d.ts +19 -0
- package/dist/internal/bridge/transport.d.ts.map +1 -0
- package/dist/internal/bridge/transport.js +66 -0
- package/dist/internal/bridge/transport.js.map +1 -0
- package/dist/internal/capabilities/auth.d.ts +55 -0
- package/dist/internal/capabilities/auth.d.ts.map +1 -0
- package/dist/internal/capabilities/auth.js +361 -0
- package/dist/internal/capabilities/auth.js.map +1 -0
- package/dist/internal/capabilities/device.d.ts +11 -0
- package/dist/internal/capabilities/device.d.ts.map +1 -0
- package/dist/internal/capabilities/device.js +65 -0
- package/dist/internal/capabilities/device.js.map +1 -0
- package/dist/internal/env.d.ts +14 -0
- package/dist/internal/env.d.ts.map +1 -0
- package/dist/internal/env.js +28 -0
- package/dist/internal/env.js.map +1 -0
- package/dist/internal/login-ui/icons.d.ts +18 -0
- package/dist/internal/login-ui/icons.d.ts.map +1 -0
- package/dist/internal/login-ui/icons.js +62 -0
- package/dist/internal/login-ui/icons.js.map +1 -0
- package/dist/internal/login-ui/index.d.ts +3 -0
- package/dist/internal/login-ui/index.d.ts.map +1 -0
- package/dist/internal/login-ui/index.js +160 -0
- package/dist/internal/login-ui/index.js.map +1 -0
- package/dist/internal/login-ui/styles.d.ts +3 -0
- package/dist/internal/login-ui/styles.d.ts.map +1 -0
- package/dist/internal/login-ui/styles.js +282 -0
- package/dist/internal/login-ui/styles.js.map +1 -0
- package/dist/internal/store.d.ts +29 -0
- package/dist/internal/store.d.ts.map +1 -0
- package/dist/internal/store.js +82 -0
- package/dist/internal/store.js.map +1 -0
- package/dist/react.d.ts +24 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +81 -0
- package/dist/react.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +53 -0
- package/dist/server.js.map +1 -0
- package/dist/testing.d.ts +13 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +38 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +71 -0
package/PROTOCOL.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Eazo SDK Protocol (v1)
|
|
2
|
+
|
|
3
|
+
This document specifies the `postMessage` protocol between an Eazo app (web) and its host (Eazo Mobile WebView, or an iframe embed). `@eazo/sdk` is the reference implementation on the app side; host implementations (mobile, backend-driven embed) must conform to this spec.
|
|
4
|
+
|
|
5
|
+
## Transport
|
|
6
|
+
|
|
7
|
+
- Channel: `eazo-sdk`
|
|
8
|
+
- Version: `1`
|
|
9
|
+
- Encoding: JSON string
|
|
10
|
+
- App → host: `window.ReactNativeWebView.postMessage(payload)` (RN WebView) or `window.parent.postMessage(payload, "*")` (iframe)
|
|
11
|
+
- Host → app: environment-specific `postMessage` dispatch
|
|
12
|
+
|
|
13
|
+
Every envelope carries `ch: "eazo-sdk"` and `v: 1`. Messages that don't match are silently ignored — the SDK and host must co-exist with other libraries that also use `postMessage`.
|
|
14
|
+
|
|
15
|
+
## Envelope types
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
type Envelope =
|
|
19
|
+
| Ready // app → host
|
|
20
|
+
| Hello // host → app (in response to Ready)
|
|
21
|
+
| Request // app → host
|
|
22
|
+
| Response // host → app (in response to Request)
|
|
23
|
+
| Event; // host → app (unsolicited)
|
|
24
|
+
|
|
25
|
+
interface Ready { ch: "eazo-sdk"; v: 1; t: "ready"; }
|
|
26
|
+
|
|
27
|
+
interface Hello {
|
|
28
|
+
ch: "eazo-sdk"; v: 1; t: "hello";
|
|
29
|
+
session: { authenticated: boolean; user: User | null; token: string | null };
|
|
30
|
+
device: DeviceContext;
|
|
31
|
+
capabilities: string[]; // e.g. ["auth.*", "device.getContext", "storage.get"]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface Request { ch: "eazo-sdk"; v: 1; t: "req"; id: string; fn: string; args?: unknown; }
|
|
35
|
+
|
|
36
|
+
interface ResponseOk { ch: "eazo-sdk"; v: 1; t: "res"; id: string; ok: true; data?: unknown; }
|
|
37
|
+
interface ResponseErr{ ch: "eazo-sdk"; v: 1; t: "res"; id: string; ok: false; err: BridgeError; }
|
|
38
|
+
|
|
39
|
+
interface Event { ch: "eazo-sdk"; v: 1; t: "evt"; name: string; data?: unknown; }
|
|
40
|
+
|
|
41
|
+
interface BridgeError {
|
|
42
|
+
code: "NOT_SUPPORTED" | "TIMEOUT" | "DENIED" | "INVALID_ARGS" | "INTERNAL";
|
|
43
|
+
message: string;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Handshake
|
|
48
|
+
|
|
49
|
+
1. App mounts → sends `{ t: "ready" }`
|
|
50
|
+
2. Host responds with `{ t: "hello", session, device, capabilities }`
|
|
51
|
+
3. App caches the hello payload as initial state; subsequent RPCs and events apply to this cache
|
|
52
|
+
4. If the app does not receive `hello` within **1.5 s**, it enters pure-web mode (no further requests are sent)
|
|
53
|
+
|
|
54
|
+
## RPC
|
|
55
|
+
|
|
56
|
+
- `id` is app-generated, unique per session (UUID or counter)
|
|
57
|
+
- Response MUST echo the same `id`
|
|
58
|
+
- Timeout: **10 s** — if no response arrives, the app throws `TIMEOUT`
|
|
59
|
+
|
|
60
|
+
## Method and event naming
|
|
61
|
+
|
|
62
|
+
- Method names (`fn`): `<capability>.<action>`; action is camelCase
|
|
63
|
+
- Examples: `auth.getToken`, `auth.getSession`, `device.getContext`, `storage.get`
|
|
64
|
+
- Event names (`name`): `<capability>.<event>`; past tense or state descriptor
|
|
65
|
+
- Examples: `auth.changed`, `device.safeArea.changed`
|
|
66
|
+
|
|
67
|
+
## Capability advertisement
|
|
68
|
+
|
|
69
|
+
Host declares which functions it supports in `hello.capabilities`. Format:
|
|
70
|
+
|
|
71
|
+
- `auth.*` — all `auth.<anything>` supported
|
|
72
|
+
- `auth.getToken` — only this specific method
|
|
73
|
+
|
|
74
|
+
The app checks this list before sending a request; unsupported methods fail immediately with `NOT_SUPPORTED` (app then falls back to web-native behavior).
|
|
75
|
+
|
|
76
|
+
## Error semantics
|
|
77
|
+
|
|
78
|
+
| Code | Meaning | App behavior |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `NOT_SUPPORTED` | Method not advertised in `capabilities` | Fall back to web-native |
|
|
81
|
+
| `TIMEOUT` | No response in 10 s | Fall back to web-native |
|
|
82
|
+
| `DENIED` | Host / user refused (permission, policy) | Surface to business code |
|
|
83
|
+
| `INVALID_ARGS` | Request args failed validation | Surface to business code |
|
|
84
|
+
| `INTERNAL` | Host error | Log + surface |
|
|
85
|
+
|
|
86
|
+
## First-version method and event catalog
|
|
87
|
+
|
|
88
|
+
### Methods
|
|
89
|
+
|
|
90
|
+
| `fn` | `args` | `data` | Notes |
|
|
91
|
+
|---|---|---|---|
|
|
92
|
+
| `auth.getToken` | — | `{ token: string \| null }` | Current session token |
|
|
93
|
+
| `auth.getSession` | — | `{ session: SessionToken \| null }` | Raw encrypted session (`x-eazo-session` payload) |
|
|
94
|
+
| `auth.requestLogin` | `{ preferredProvider?: string }` (optional) | `{ started: boolean }` | Host should display its native login UI and return promptly (don't block on user). The SDK then waits for `auth.changed` (success) or `auth.loginCancelled` (dismiss). If the host can't show native UI, respond `NOT_SUPPORTED` — SDK falls back to the web login UI inside the WebView. |
|
|
95
|
+
| `device.getContext` | — | `DeviceContext` | Usually unused — hello already contains this |
|
|
96
|
+
|
|
97
|
+
### Events
|
|
98
|
+
|
|
99
|
+
| `name` | `data` | Trigger |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `auth.changed` | `{ authenticated, user, token }` | Login, logout, account switch |
|
|
102
|
+
| `auth.loginCancelled` | — (optional `{ reason?: string }`) | User dismissed the native login UI without authenticating. Causes the app's in-flight `auth.login()` to reject with `DENIED`. |
|
|
103
|
+
| `device.safeArea.changed` | `{ top?, bottom? }` | Keyboard / orientation |
|
|
104
|
+
|
|
105
|
+
## Version evolution
|
|
106
|
+
|
|
107
|
+
- **Breaking change** → bump `v`; host replies `NOT_SUPPORTED` if mismatched
|
|
108
|
+
- **New capability** → append to `capabilities` only; v stays
|
|
109
|
+
- **Method arg change** → new fields optional (backward-compatible); incompatible changes use a new method name
|
|
110
|
+
|
|
111
|
+
## Minimal host implementation
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
window.addEventListener("message", (e) => {
|
|
115
|
+
const msg = typeof e.data === "string" ? JSON.parse(e.data) : e.data;
|
|
116
|
+
if (msg?.ch !== "eazo-sdk" || msg.v !== 1) return;
|
|
117
|
+
|
|
118
|
+
if (msg.t === "ready") {
|
|
119
|
+
send({
|
|
120
|
+
ch: "eazo-sdk", v: 1, t: "hello",
|
|
121
|
+
session: { authenticated: true, user, token },
|
|
122
|
+
device: { platform: "mobile", locale: "zh-CN",
|
|
123
|
+
safeArea: { top: 44, bottom: 34 }, backendUrl: "https://api.eazo.ai" },
|
|
124
|
+
capabilities: ["auth.*"],
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (msg.t === "req" && msg.fn === "auth.getToken") {
|
|
129
|
+
send({ ch: "eazo-sdk", v: 1, t: "res", id: msg.id, ok: true, data: { token } });
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Hosts that don't implement an advertised method must respond with `ok: false, err: { code: "NOT_SUPPORTED", ... }`.
|
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @eazo/sdk
|
|
2
|
+
|
|
3
|
+
Capability-first SDK for web apps that run both on a standard browser and inside the Eazo Mobile WebView. Write one codebase; the SDK picks the right implementation for the runtime.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @eazo/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
// app/layout.tsx
|
|
15
|
+
import { EazoProvider } from "@eazo/sdk/react";
|
|
16
|
+
|
|
17
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
18
|
+
return <EazoProvider>{children}</EazoProvider>;
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
// Any component
|
|
24
|
+
import { auth } from "@eazo/sdk";
|
|
25
|
+
import { useEazo } from "@eazo/sdk/react";
|
|
26
|
+
|
|
27
|
+
export function Header() {
|
|
28
|
+
const user = useEazo((s) => s.auth.user);
|
|
29
|
+
if (!user) return <button onClick={() => auth.loginWithSocial("google")}>Sign in</button>;
|
|
30
|
+
return <span>Hi, {user.name}</span>;
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## API
|
|
35
|
+
|
|
36
|
+
### `auth`
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { auth } from "@eazo/sdk";
|
|
40
|
+
|
|
41
|
+
auth.user // User | null
|
|
42
|
+
auth.loading // boolean
|
|
43
|
+
auth.authenticated // boolean
|
|
44
|
+
auth.loginUIOpen // boolean (web login UI)
|
|
45
|
+
await auth.getToken() // string | null
|
|
46
|
+
auth.onChange((user) => { ... }) // () => void (unsubscribe)
|
|
47
|
+
|
|
48
|
+
// One-stop login — handles every runtime and idempotent if already signed in.
|
|
49
|
+
const user = await auth.login() // User
|
|
50
|
+
await auth.login({ timeoutMs: 120_000 }) // custom timeout (default: 5 min)
|
|
51
|
+
auth.showLogin() // imperative open (no await)
|
|
52
|
+
auth.hideLogin() // imperative close (rejects pending login())
|
|
53
|
+
|
|
54
|
+
// Low-level login primitives (rarely needed; `login()` orchestrates these).
|
|
55
|
+
await auth.loginWithSocial("google")
|
|
56
|
+
await auth.loginWithEmailPassword(email, password)
|
|
57
|
+
await auth.loginWithEmailCode(email, code)
|
|
58
|
+
await auth.sendEmailCode(email)
|
|
59
|
+
await auth.logout()
|
|
60
|
+
|
|
61
|
+
auth.fetchSocialConnections() // SocialConnection[]
|
|
62
|
+
auth.configure({ publicKey: "..." }) // set developer public key
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
By default the SDK reads `NEXT_PUBLIC_EAZO_PUBLIC_KEY` from the environment. Call `auth.configure({ publicKey })` if you need to set it explicitly.
|
|
66
|
+
|
|
67
|
+
#### `auth.login()` — unified login flow
|
|
68
|
+
|
|
69
|
+
`auth.login()` is the canonical way to sign a user in. It:
|
|
70
|
+
|
|
71
|
+
1. Returns the current user immediately if already authenticated (idempotent).
|
|
72
|
+
2. On Eazo Mobile (host advertises `auth.requestLogin`), delegates to the native host login UI.
|
|
73
|
+
3. Otherwise, shows the SDK-bundled login modal (social providers + email / code / password).
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
<button onClick={async () => {
|
|
77
|
+
await auth.login();
|
|
78
|
+
doSomethingProtected();
|
|
79
|
+
}}>
|
|
80
|
+
Do something
|
|
81
|
+
</button>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
It rejects with `DENIED` if the user cancels, or `TIMEOUT` after 5 minutes of inactivity (configurable via `timeoutMs`).
|
|
85
|
+
|
|
86
|
+
### `device`
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { device } from "@eazo/sdk";
|
|
90
|
+
|
|
91
|
+
device.platform // 'web' | 'mobile'
|
|
92
|
+
device.locale // 'zh-CN' | ...
|
|
93
|
+
device.safeArea // { top: number; bottom: number }
|
|
94
|
+
device.backendUrl // '' when running web-only
|
|
95
|
+
device.getContext() // full DeviceContext
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### React integration
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { EazoProvider, useEazo } from "@eazo/sdk/react";
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Rule: inside React render, read reactive state via `useEazo(selector)`. Outside render (event handlers, effects, non-React code), read directly from `auth.xxx` / `device.xxx`.
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
const user = useEazo((s) => s.auth.user);
|
|
108
|
+
const { platform, safeArea } = useEazo((s) => s.device);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Server (Next.js route handler)
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { requireAuth } from "@eazo/sdk/server";
|
|
115
|
+
|
|
116
|
+
export function GET(req: NextRequest) {
|
|
117
|
+
const r = requireAuth(req);
|
|
118
|
+
if (!r.ok) return r.response;
|
|
119
|
+
// r.user: User
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Requires `EAZO_PRIVATE_KEY` in the server environment.
|
|
124
|
+
|
|
125
|
+
### Testing
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { __resetSDK, __dispatchHostMessage } from "@eazo/sdk/testing";
|
|
129
|
+
|
|
130
|
+
afterEach(() => __resetSDK());
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Types
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
interface User {
|
|
137
|
+
id: string;
|
|
138
|
+
email: string | null;
|
|
139
|
+
name: string | null;
|
|
140
|
+
avatarUrl: string | null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
interface DeviceContext {
|
|
144
|
+
platform: "web" | "mobile";
|
|
145
|
+
locale: string;
|
|
146
|
+
safeArea: { top: number; bottom: number };
|
|
147
|
+
backendUrl: string;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## How it works
|
|
152
|
+
|
|
153
|
+
The SDK talks to the Eazo Mobile host over `postMessage` using the protocol documented in [PROTOCOL.md](./PROTOCOL.md). When no host responds within 1.5 seconds, the SDK falls back to web-native implementations (GenAuth for login, `localStorage` for session, `navigator.language` for locale).
|
|
154
|
+
|
|
155
|
+
App code never branches on environment — the capability API is the same on both platforms.
|
|
156
|
+
|
|
157
|
+
## Environment
|
|
158
|
+
|
|
159
|
+
| Variable | Required | Used by |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| `NEXT_PUBLIC_EAZO_PUBLIC_KEY` | web login | `auth.loginWith*` |
|
|
162
|
+
| `NEXT_PUBLIC_EAZO_API_URL` | optional | default `backendUrl` when web-only |
|
|
163
|
+
| `EAZO_PRIVATE_KEY` | server | `requireAuth` |
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { auth } from "./internal/capabilities/auth";
|
|
2
|
+
export { device } from "./internal/capabilities/device";
|
|
3
|
+
export type { LoginOptions } from "./internal/capabilities/auth";
|
|
4
|
+
export type { User, DeviceContext, AuthState, EazoState } from "./types";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAExD,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.device = exports.auth = void 0;
|
|
4
|
+
var auth_1 = require("./internal/capabilities/auth");
|
|
5
|
+
Object.defineProperty(exports, "auth", { enumerable: true, get: function () { return auth_1.auth; } });
|
|
6
|
+
var device_1 = require("./internal/capabilities/device");
|
|
7
|
+
Object.defineProperty(exports, "device", { enumerable: true, get: function () { return device_1.device; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qDAAoD;AAA3C,4FAAA,IAAI,OAAA;AACb,yDAAwD;AAA/C,gGAAA,MAAM,OAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AuthenticationClient } from "authing-js-sdk";
|
|
2
|
+
import type { EazoAuthClientConfig, SessionToken, SocialConnection } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Browser-side auth primitive. Wraps GenAuth (Authing) to exchange a JWT for
|
|
5
|
+
* an encrypted SessionToken (same shape produced by Eazo Mobile).
|
|
6
|
+
*
|
|
7
|
+
* The SDK's `auth` capability wraps this; app code should go through that
|
|
8
|
+
* capability (auth.loginWithSocial / loginWithEmailPassword / loginWithEmailCode)
|
|
9
|
+
* rather than using EazoAuthClient directly.
|
|
10
|
+
*/
|
|
11
|
+
export declare class EazoAuthClient {
|
|
12
|
+
private readonly publicKey;
|
|
13
|
+
private readonly authAppId;
|
|
14
|
+
private readonly authAppDomain;
|
|
15
|
+
private readonly apiBase;
|
|
16
|
+
private _authingClient;
|
|
17
|
+
constructor(config: EazoAuthClientConfig);
|
|
18
|
+
/**
|
|
19
|
+
* Exchanges a GenAuth JWT for an encrypted session token.
|
|
20
|
+
* The resulting token has the same shape as Eazo Mobile's session,
|
|
21
|
+
* so the server always decrypts it with EAZO_PRIVATE_KEY.
|
|
22
|
+
*/
|
|
23
|
+
private _getSessionToken;
|
|
24
|
+
/** Initiates a social login popup and returns an encrypted session token. */
|
|
25
|
+
loginWithSocial(extIdpIdentifier: string): Promise<SessionToken>;
|
|
26
|
+
/** Logs in with email + password and returns an encrypted session token. */
|
|
27
|
+
loginWithEmailPassword(email: string, password: string): Promise<SessionToken>;
|
|
28
|
+
/** Logs in with email + verification code and returns an encrypted session token. */
|
|
29
|
+
loginWithEmailCode(email: string, code: string): Promise<SessionToken>;
|
|
30
|
+
/** Sends an email verification code for login. */
|
|
31
|
+
sendEmailCode(email: string): Promise<void>;
|
|
32
|
+
getAuthingClient(): AuthenticationClient;
|
|
33
|
+
fetchSocialConnections(): Promise<SocialConnection[]>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=EazoAuthClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EazoAuthClient.d.ts","sourceRoot":"","sources":["../../../src/internal/auth-primitive/EazoAuthClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAc,MAAM,gBAAgB,CAAC;AAElE,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAMpF;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO,CAAC,cAAc,CAAqC;gBAE/C,MAAM,EAAE,oBAAoB;IAQxC;;;;OAIG;YACW,gBAAgB;IAkB9B,6EAA6E;IAC7E,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAqBhE,4EAA4E;IACtE,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAUpF,qFAAqF;IAC/E,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAU5E,kDAAkD;IAC5C,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,gBAAgB,IAAI,oBAAoB;IASlC,sBAAsB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAS5D"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EazoAuthClient = void 0;
|
|
4
|
+
const authing_js_sdk_1 = require("authing-js-sdk");
|
|
5
|
+
const DEFAULT_AUTH_APP_ID = "6972f32040acf5801552404b";
|
|
6
|
+
const DEFAULT_AUTH_APP_DOMAIN = "https://eazo.genauth.ai";
|
|
7
|
+
const DEFAULT_API_BASE = "https://eazo.ai";
|
|
8
|
+
/**
|
|
9
|
+
* Browser-side auth primitive. Wraps GenAuth (Authing) to exchange a JWT for
|
|
10
|
+
* an encrypted SessionToken (same shape produced by Eazo Mobile).
|
|
11
|
+
*
|
|
12
|
+
* The SDK's `auth` capability wraps this; app code should go through that
|
|
13
|
+
* capability (auth.loginWithSocial / loginWithEmailPassword / loginWithEmailCode)
|
|
14
|
+
* rather than using EazoAuthClient directly.
|
|
15
|
+
*/
|
|
16
|
+
class EazoAuthClient {
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this._authingClient = null;
|
|
19
|
+
if (!config.publicKey)
|
|
20
|
+
throw new Error("@eazo/sdk: publicKey is required");
|
|
21
|
+
this.publicKey = config.publicKey;
|
|
22
|
+
this.authAppId = config.authAppId ?? DEFAULT_AUTH_APP_ID;
|
|
23
|
+
this.authAppDomain = config.authAppDomain ?? DEFAULT_AUTH_APP_DOMAIN;
|
|
24
|
+
this.apiBase = config.apiBase ?? DEFAULT_API_BASE;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Exchanges a GenAuth JWT for an encrypted session token.
|
|
28
|
+
* The resulting token has the same shape as Eazo Mobile's session,
|
|
29
|
+
* so the server always decrypts it with EAZO_PRIVATE_KEY.
|
|
30
|
+
*/
|
|
31
|
+
async _getSessionToken(jwt) {
|
|
32
|
+
const res = await fetch(`${this.apiBase}/api/open/app-session-token`, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: {
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
"Authorization": `Bearer ${jwt}`,
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify({ publicKey: this.publicKey }),
|
|
39
|
+
});
|
|
40
|
+
if (!res.ok) {
|
|
41
|
+
throw new Error(`Failed to get session token: ${res.status}`);
|
|
42
|
+
}
|
|
43
|
+
const json = await res.json();
|
|
44
|
+
return json.data;
|
|
45
|
+
}
|
|
46
|
+
/** Initiates a social login popup and returns an encrypted session token. */
|
|
47
|
+
loginWithSocial(extIdpIdentifier) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const client = this.getAuthingClient();
|
|
50
|
+
client.social.authorize(extIdpIdentifier, {
|
|
51
|
+
onSuccess: async (profile) => {
|
|
52
|
+
try {
|
|
53
|
+
const p = profile;
|
|
54
|
+
const jwt = (p.token ?? p.id_token);
|
|
55
|
+
if (!jwt)
|
|
56
|
+
throw new Error("Social login succeeded but no token received");
|
|
57
|
+
resolve(await this._getSessionToken(jwt));
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
reject(err);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
onError: (code, message) => {
|
|
64
|
+
reject(new Error(message || `Social login failed (${code})`));
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/** Logs in with email + password and returns an encrypted session token. */
|
|
70
|
+
async loginWithEmailPassword(email, password) {
|
|
71
|
+
const result = (await this.getAuthingClient().loginByEmail(email, password));
|
|
72
|
+
const jwt = (result.token ?? result.id_token);
|
|
73
|
+
if (!jwt)
|
|
74
|
+
throw new Error("Login succeeded but no token received");
|
|
75
|
+
return this._getSessionToken(jwt);
|
|
76
|
+
}
|
|
77
|
+
/** Logs in with email + verification code and returns an encrypted session token. */
|
|
78
|
+
async loginWithEmailCode(email, code) {
|
|
79
|
+
const result = (await this.getAuthingClient().loginByEmailCode(email, code));
|
|
80
|
+
const jwt = (result.token ?? result.id_token);
|
|
81
|
+
if (!jwt)
|
|
82
|
+
throw new Error("Login succeeded but no token received");
|
|
83
|
+
return this._getSessionToken(jwt);
|
|
84
|
+
}
|
|
85
|
+
/** Sends an email verification code for login. */
|
|
86
|
+
async sendEmailCode(email) {
|
|
87
|
+
await this.getAuthingClient().sendEmail(email, authing_js_sdk_1.EmailScene.LOGIN_VERIFY_CODE);
|
|
88
|
+
}
|
|
89
|
+
getAuthingClient() {
|
|
90
|
+
if (this._authingClient)
|
|
91
|
+
return this._authingClient;
|
|
92
|
+
this._authingClient = new authing_js_sdk_1.AuthenticationClient({
|
|
93
|
+
appId: this.authAppId,
|
|
94
|
+
appHost: this.authAppDomain,
|
|
95
|
+
});
|
|
96
|
+
return this._authingClient;
|
|
97
|
+
}
|
|
98
|
+
async fetchSocialConnections() {
|
|
99
|
+
const res = await fetch(`${this.authAppDomain}/api/v2/applications/${this.authAppId}/public-config`, { next: { revalidate: 3600 } });
|
|
100
|
+
if (!res.ok)
|
|
101
|
+
throw new Error(`Failed to fetch GenAuth public config: ${res.status}`);
|
|
102
|
+
const json = await res.json();
|
|
103
|
+
return json.data.socialConnections;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.EazoAuthClient = EazoAuthClient;
|
|
107
|
+
//# sourceMappingURL=EazoAuthClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EazoAuthClient.js","sourceRoot":"","sources":["../../../src/internal/auth-primitive/EazoAuthClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { EazoAuthServerConfig, SessionToken, UserInfo } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Server-side auth verifier. Decrypts an encrypted session token (produced by
|
|
4
|
+
* the Eazo Mobile bridge or the /api/open/app-session-token exchange) using
|
|
5
|
+
* EAZO_PRIVATE_KEY. Both Mobile and Web produce the same SessionToken shape,
|
|
6
|
+
* so verification is a single code path with no environment detection.
|
|
7
|
+
*/
|
|
8
|
+
export declare class EazoAuthServer {
|
|
9
|
+
private readonly privateKey;
|
|
10
|
+
constructor(config: EazoAuthServerConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Decrypts a session token and returns the user's identity.
|
|
13
|
+
* @param session - The parsed x-eazo-session payload (encryptedData, encryptedKey, iv, authTag).
|
|
14
|
+
* @throws if the token is missing required fields or decryption fails.
|
|
15
|
+
*/
|
|
16
|
+
verifySession(session: SessionToken): UserInfo;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=EazoAuthServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EazoAuthServer.d.ts","sourceRoot":"","sources":["../../../src/internal/auth-primitive/EazoAuthServer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5E;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,MAAM,EAAE,oBAAoB;IAKxC;;;;OAIG;IACH,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,QAAQ;CAa/C"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EazoAuthServer = void 0;
|
|
4
|
+
const decrypt_1 = require("./decrypt");
|
|
5
|
+
/**
|
|
6
|
+
* Server-side auth verifier. Decrypts an encrypted session token (produced by
|
|
7
|
+
* the Eazo Mobile bridge or the /api/open/app-session-token exchange) using
|
|
8
|
+
* EAZO_PRIVATE_KEY. Both Mobile and Web produce the same SessionToken shape,
|
|
9
|
+
* so verification is a single code path with no environment detection.
|
|
10
|
+
*/
|
|
11
|
+
class EazoAuthServer {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
if (!config.privateKey)
|
|
14
|
+
throw new Error("@eazo/sdk: privateKey is required");
|
|
15
|
+
this.privateKey = config.privateKey;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Decrypts a session token and returns the user's identity.
|
|
19
|
+
* @param session - The parsed x-eazo-session payload (encryptedData, encryptedKey, iv, authTag).
|
|
20
|
+
* @throws if the token is missing required fields or decryption fails.
|
|
21
|
+
*/
|
|
22
|
+
verifySession(session) {
|
|
23
|
+
const { encryptedData, encryptedKey, iv, authTag } = session;
|
|
24
|
+
if (!encryptedData || !encryptedKey || !iv || !authTag) {
|
|
25
|
+
throw new Error("Incomplete session token");
|
|
26
|
+
}
|
|
27
|
+
return (0, decrypt_1.decryptUserInfo)({
|
|
28
|
+
encryptedData,
|
|
29
|
+
encryptedKey,
|
|
30
|
+
iv,
|
|
31
|
+
authTag,
|
|
32
|
+
privateKey: this.privateKey,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.EazoAuthServer = EazoAuthServer;
|
|
37
|
+
//# sourceMappingURL=EazoAuthServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EazoAuthServer.js","sourceRoot":"","sources":["../../../src/internal/auth-primitive/EazoAuthServer.ts"],"names":[],"mappings":";;;AAAA,uCAA4C;AAG5C;;;;;GAKG;AACH,MAAa,cAAc;IAGzB,YAAY,MAA4B;QACtC,IAAI,CAAC,MAAM,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAC7E,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACtC,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,OAAqB;QACjC,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAC7D,IAAI,CAAC,aAAa,IAAI,CAAC,YAAY,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,IAAA,yBAAe,EAAC;YACrB,aAAa;YACb,YAAY;YACZ,EAAE;YACF,OAAO;YACP,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC,CAAC;IACL,CAAC;CACF;AA1BD,wCA0BC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DecryptOptions, DecryptResult, UserInfo } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Decrypt data encrypted with ECC secp256k1 + AES-256-GCM hybrid encryption.
|
|
4
|
+
*
|
|
5
|
+
* Two-stage process:
|
|
6
|
+
* 1. ECDH shared secret + SHA-256 → AES-256-CBC to unwrap the AES key
|
|
7
|
+
* 2. AES-256-GCM with the unwrapped key to decrypt the payload
|
|
8
|
+
*/
|
|
9
|
+
export declare function decrypt<T = unknown>(options: DecryptOptions): DecryptResult<T>;
|
|
10
|
+
/** Convenience wrapper — decrypts and returns a typed UserInfo object. */
|
|
11
|
+
export declare function decryptUserInfo(options: DecryptOptions): UserInfo;
|
|
12
|
+
//# sourceMappingURL=decrypt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decrypt.d.ts","sourceRoot":"","sources":["../../../src/internal/auth-primitive/decrypt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIvE;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,cAAc,GAAG,aAAa,CAAC,CAAC,CAAC,CA4C9E;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,QAAQ,CAGjE"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.decrypt = decrypt;
|
|
37
|
+
exports.decryptUserInfo = decryptUserInfo;
|
|
38
|
+
const crypto = __importStar(require("crypto"));
|
|
39
|
+
const elliptic_1 = require("elliptic");
|
|
40
|
+
const ec = new elliptic_1.ec("secp256k1");
|
|
41
|
+
/**
|
|
42
|
+
* Decrypt data encrypted with ECC secp256k1 + AES-256-GCM hybrid encryption.
|
|
43
|
+
*
|
|
44
|
+
* Two-stage process:
|
|
45
|
+
* 1. ECDH shared secret + SHA-256 → AES-256-CBC to unwrap the AES key
|
|
46
|
+
* 2. AES-256-GCM with the unwrapped key to decrypt the payload
|
|
47
|
+
*/
|
|
48
|
+
function decrypt(options) {
|
|
49
|
+
const { encryptedData, encryptedKey, iv, authTag, privateKey } = options;
|
|
50
|
+
if (!encryptedData || !encryptedKey || !iv || !authTag || !privateKey) {
|
|
51
|
+
throw new Error("Missing required decryption parameters");
|
|
52
|
+
}
|
|
53
|
+
if (!/^[0-9a-f]{64}$/i.test(privateKey)) {
|
|
54
|
+
throw new Error("Invalid private key — expected 64 hex characters");
|
|
55
|
+
}
|
|
56
|
+
const keyPair = ec.keyFromPrivate(privateKey, "hex");
|
|
57
|
+
const encKeyBuf = Buffer.from(encryptedKey, "base64");
|
|
58
|
+
const EPHEMERAL_PUBKEY_LEN = 33; // secp256k1 compressed
|
|
59
|
+
const ephemeralPubKeyHex = encKeyBuf.slice(0, EPHEMERAL_PUBKEY_LEN).toString("hex");
|
|
60
|
+
const cipherIv = encKeyBuf.slice(EPHEMERAL_PUBKEY_LEN, EPHEMERAL_PUBKEY_LEN + 16);
|
|
61
|
+
const cipherText = encKeyBuf.slice(EPHEMERAL_PUBKEY_LEN + 16);
|
|
62
|
+
const ephemeralPubKey = ec.keyFromPublic(ephemeralPubKeyHex, "hex");
|
|
63
|
+
const sharedSecret = keyPair.derive(ephemeralPubKey.getPublic());
|
|
64
|
+
const sharedSecretBuf = Buffer.from(sharedSecret.toString(16).padStart(64, "0"), "hex");
|
|
65
|
+
const decryptionKey = crypto.createHash("sha256").update(sharedSecretBuf).digest();
|
|
66
|
+
const decipher1 = crypto.createDecipheriv("aes-256-cbc", decryptionKey, cipherIv);
|
|
67
|
+
const aesKey = Buffer.concat([decipher1.update(cipherText), decipher1.final()]);
|
|
68
|
+
const ivBuf = Buffer.from(iv, "base64");
|
|
69
|
+
const authTagBuf = Buffer.from(authTag, "base64");
|
|
70
|
+
const encDataBuf = Buffer.from(encryptedData, "base64");
|
|
71
|
+
const decipher2 = crypto.createDecipheriv("aes-256-gcm", aesKey, ivBuf);
|
|
72
|
+
decipher2.setAuthTag(authTagBuf);
|
|
73
|
+
let raw = decipher2.update(encDataBuf, undefined, "utf8");
|
|
74
|
+
raw += decipher2.final("utf8");
|
|
75
|
+
let data;
|
|
76
|
+
try {
|
|
77
|
+
data = JSON.parse(raw);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
data = raw;
|
|
81
|
+
}
|
|
82
|
+
return { data, raw };
|
|
83
|
+
}
|
|
84
|
+
/** Convenience wrapper — decrypts and returns a typed UserInfo object. */
|
|
85
|
+
function decryptUserInfo(options) {
|
|
86
|
+
const result = decrypt(options);
|
|
87
|
+
return result.data;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=decrypt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decrypt.js","sourceRoot":"","sources":["../../../src/internal/auth-primitive/decrypt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { EazoAuthClient } from "./EazoAuthClient";
|
|
2
|
+
export { EazoAuthServer } from "./EazoAuthServer";
|
|
3
|
+
export { decrypt, decryptUserInfo } from "./decrypt";
|
|
4
|
+
export type { DecryptOptions, DecryptResult, EazoAuthClientConfig, EazoAuthServerConfig, SessionToken, SocialConnection, UserInfo, } from "./types";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|