@volter/twin-xidentity 0.1.0 → 0.1.2
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 +37 -4
- package/client/xidentity-consent.tsx +41 -4
- package/dist/client/xidentity-consent.bundle.js +85 -85
- package/dist/client/xidentity-consent.d.ts +17 -1
- package/dist/client/xidentity-consent.js +11 -2
- package/dist/client/xidentity-consent.tsx +41 -4
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +16 -8
- package/dist/src/xidentity-capabilities.js +243 -8
- package/dist/src/xidentity-conformance.d.ts +41 -0
- package/dist/src/xidentity-conformance.js +210 -3
- package/dist/src/xidentity-consent-client.gen.d.ts +1 -1
- package/dist/src/xidentity-consent-client.gen.js +1 -1
- package/dist/src/xidentity-consent-ui.d.ts +25 -1
- package/dist/src/xidentity-consent-ui.js +62 -1
- package/dist/src/xidentity-oauth1.d.ts +93 -0
- package/dist/src/xidentity-oauth1.js +594 -0
- package/dist/src/xidentity-server.js +14 -4
- package/dist/src/xidentity-store.d.ts +4 -1
- package/dist/src/xidentity-store.js +8 -1
- package/dist/src/xidentity-twin.js +32 -9
- package/package.json +5 -4
- package/src/index.ts +30 -8
- package/src/xidentity-capabilities.ts +254 -8
- package/src/xidentity-conformance.ts +232 -3
- package/src/xidentity-consent-client.gen.ts +1 -1
- package/src/xidentity-consent-ui.ts +67 -0
- package/src/xidentity-oauth1.ts +598 -0
- package/src/xidentity-server.ts +14 -4
- package/src/xidentity-store.ts +8 -1
- package/src/xidentity-twin.ts +30 -9
|
@@ -21,6 +21,7 @@ import { renderToStaticMarkup } from 'react-dom/server';
|
|
|
21
21
|
import {
|
|
22
22
|
ConsentPage,
|
|
23
23
|
ErrorPage,
|
|
24
|
+
PinPage,
|
|
24
25
|
type ConsentAccount,
|
|
25
26
|
type ConsentScopeRow,
|
|
26
27
|
type ConsentView,
|
|
@@ -88,6 +89,67 @@ export function xIdentityConsentState(opts: {
|
|
|
88
89
|
};
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
/**
|
|
93
|
+
* What an OAuth 1.0a token lets an app do, as X's authorize screen lists it. OAuth 1.0a has no
|
|
94
|
+
* scopes: the App's permission level (Read / Read and write) decides the grant (docs.x.com
|
|
95
|
+
* developer-apps, "App permissions (OAuth 1.0a)"), and the screen lists what that level allows.
|
|
96
|
+
* The lines follow X's OAuth 1.0a authorize page as widely screenshotted; the live wording was not
|
|
97
|
+
* captured (`xidentity.oauth1.consent_wording`, todo). Keyed rows, so a row is never invented
|
|
98
|
+
* outside the two documented levels.
|
|
99
|
+
*/
|
|
100
|
+
export const OAUTH1_CONSENT_ROWS: Record<'read' | 'write', ConsentScopeRow[]> = {
|
|
101
|
+
read: [
|
|
102
|
+
{ scope: 'oauth1:timeline', label: 'Posts from your timeline (including protected Posts) as well as your Lists and collections.', group: 'view', known: true },
|
|
103
|
+
{ scope: 'oauth1:profile', label: 'Your X profile information and account settings.', group: 'view', known: true },
|
|
104
|
+
{ scope: 'oauth1:graph', label: 'Accounts you follow, mute, and block.', group: 'view', known: true },
|
|
105
|
+
],
|
|
106
|
+
write: [
|
|
107
|
+
{ scope: 'oauth1:follow', label: 'Follow and unfollow accounts for you.', group: 'do', known: true },
|
|
108
|
+
{ scope: 'oauth1:settings', label: 'Update your profile and account settings for you.', group: 'do', known: true },
|
|
109
|
+
{ scope: 'oauth1:post', label: 'Post and delete Posts for you, and engage with Posts posted by others (Like, un-Like, or reply to a Post, Repost, etc.) for you.', group: 'do', known: true },
|
|
110
|
+
{ scope: 'oauth1:lists', label: 'Create, manage, and delete Lists and collections for you.', group: 'do', known: true },
|
|
111
|
+
{ scope: 'oauth1:moderate', label: 'Mute, block, and report accounts for you.', group: 'do', known: true },
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* THE OAUTH 1.0a STATE BUILDER — the authorize screen for a pending request token, folded out of
|
|
117
|
+
* the projection: the App's name (`appName`, resolved by the caller from the registered App or the
|
|
118
|
+
* World's own), the account the request was bound to when the screen was first served, the rows
|
|
119
|
+
* the granted permission level allows, and the callback's host. `null` for an unknown or settled
|
|
120
|
+
* request token or a missing account; it invents nothing.
|
|
121
|
+
*/
|
|
122
|
+
export function xIdentityOAuth1ConsentState(opts: {
|
|
123
|
+
root?: string;
|
|
124
|
+
requestToken: string;
|
|
125
|
+
appName: string;
|
|
126
|
+
origin: string;
|
|
127
|
+
}): ConsentView | null {
|
|
128
|
+
const row = readOne(opts.root, 'oauth1_request_token', opts.requestToken);
|
|
129
|
+
if (!row || row.state !== 'pending') return null;
|
|
130
|
+
const account = readOne(opts.root, 'account', String(row.accountId ?? ''));
|
|
131
|
+
if (!account) return null;
|
|
132
|
+
const level = row.accessLevel === 'read' ? 'read' : 'write';
|
|
133
|
+
const scopes = level === 'read' ? OAUTH1_CONSENT_ROWS.read : [...OAUTH1_CONSENT_ROWS.read, ...OAUTH1_CONSENT_ROWS.write];
|
|
134
|
+
let redirectHost = '';
|
|
135
|
+
if (row.callback !== 'oob') {
|
|
136
|
+
try {
|
|
137
|
+
redirectHost = new URL(String(row.callback)).host;
|
|
138
|
+
} catch {
|
|
139
|
+
redirectHost = String(row.callback);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
requestId: opts.requestToken,
|
|
144
|
+
origin: opts.origin,
|
|
145
|
+
app: { clientId: String(row.consumerKey), name: opts.appName },
|
|
146
|
+
account: toConsentAccount(account),
|
|
147
|
+
scopes,
|
|
148
|
+
redirectHost,
|
|
149
|
+
decisionPath: '/oauth/authorize',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
91
153
|
/** `base` is where the twin is reached (`twinPublicBase`: origin plus any served-World mount path),
|
|
92
154
|
* so the page's assets resolve inside the World's mount; empty for an in-process render. */
|
|
93
155
|
function page(title: string, bodyMarkup: string, base: string): string {
|
|
@@ -107,6 +169,11 @@ export function consentPageHtml(view: ConsentView, base = ''): string {
|
|
|
107
169
|
return page(`Authorize ${view.app.name} to access your account? / X`, markup, base);
|
|
108
170
|
}
|
|
109
171
|
|
|
172
|
+
/** Render the out-of-band PIN page an `oob` request token ends on. */
|
|
173
|
+
export function pinPageHtml(appName: string, pin: string, base = ''): string {
|
|
174
|
+
return page(`${appName} / X`, renderToStaticMarkup(createElement(PinPage, { appName, pin })), base);
|
|
175
|
+
}
|
|
176
|
+
|
|
110
177
|
/** Render the authorize-endpoint error page (an un-redirectable failure). */
|
|
111
178
|
export function errorPageHtml(props: ErrorPageProps, base = ''): string {
|
|
112
179
|
return page(`Error ${props.status}: ${props.code} / X`, renderToStaticMarkup(createElement(ErrorPage, props)), base);
|