+23
KNOWN_ISSUES.md
+23
KNOWN_ISSUES.md
···
···
1
+
# Known Issues
2
+
3
+
## stream.place iOS app OAuth flow fails
4
+
5
+
OAuth flow with stream.place's iOS app (using expo-web-browser's ASWebAuthenticationSession) does not complete. After user approves consent, the redirect from our PDS to stream.place's callback URL is not followed by ASWebAuthenticationSession.
6
+
7
+
What does work with stream.place: everything else :P
8
+
- Desktop browsers
9
+
- ios safari (regular browser)
10
+
- ASWebAuthenticationSession using the reference pds
11
+
12
+
What fails:
13
+
- ASWebAuthenticationSession with this pds
14
+
15
+
Attempted fixes (all failed):
16
+
- HTTP 302/303/307 redirects
17
+
- JavaScript navigation
18
+
- Meta refresh
19
+
- Form auto-submit
20
+
- Removing CORS headers
21
+
- HTTP/1.1 instead of HTTP/2
22
+
- Minimal response headers
23
+
+1
-1
frontend/src/components/migration/ChooseHandleStep.svelte
+1
-1
frontend/src/components/migration/ChooseHandleStep.svelte
-18
frontend/src/routes/Admin.svelte
-18
frontend/src/routes/Admin.svelte
···
674
padding: var(--space-7);
675
}
676
677
-
.message {
678
-
padding: var(--space-3);
679
-
border-radius: var(--radius-md);
680
-
margin-bottom: var(--space-4);
681
-
}
682
-
683
-
.message.error {
684
-
background: var(--error-bg);
685
-
border: 1px solid var(--error-border);
686
-
color: var(--error-text);
687
-
}
688
-
689
-
.message.success {
690
-
background: var(--success-bg);
691
-
border: 1px solid var(--success-border);
692
-
color: var(--success-text);
693
-
}
694
-
695
.config-form {
696
max-width: 500px;
697
}
-9
frontend/src/routes/AppPasswords.svelte
-9
frontend/src/routes/AppPasswords.svelte
···
234
margin-bottom: var(--space-7);
235
}
236
237
-
.error {
238
-
padding: var(--space-3);
239
-
background: var(--error-bg);
240
-
border: 1px solid var(--error-border);
241
-
border-radius: var(--radius-md);
242
-
color: var(--error-text);
243
-
margin-bottom: var(--space-4);
244
-
}
245
-
246
.created-password {
247
display: flex;
248
flex-direction: column;
-6
frontend/src/routes/Comms.svelte
-6
frontend/src/routes/Comms.svelte
-19
frontend/src/routes/Controllers.svelte
-19
frontend/src/routes/Controllers.svelte
···
453
margin: var(--space-2) 0 0 0;
454
}
455
456
-
.loading,
457
.empty {
458
text-align: center;
459
color: var(--text-secondary);
460
padding: var(--space-4);
461
-
}
462
-
463
-
.message {
464
-
padding: var(--space-3);
465
-
border-radius: var(--radius-md);
466
-
margin-bottom: var(--space-4);
467
-
}
468
-
469
-
.message.error {
470
-
background: var(--error-bg);
471
-
border: 1px solid var(--error-border);
472
-
color: var(--error-text);
473
-
}
474
-
475
-
.message.success {
476
-
background: var(--success-bg);
477
-
border: 1px solid var(--success-border);
478
-
color: var(--success-text);
479
}
480
481
.constraint-notice {
-10
frontend/src/routes/DelegationAudit.svelte
-10
frontend/src/routes/DelegationAudit.svelte
···
216
margin: var(--space-2) 0 0 0;
217
}
218
219
-
.loading,
220
.empty {
221
text-align: center;
222
color: var(--text-secondary);
223
padding: var(--space-7);
224
-
}
225
-
226
-
.message.error {
227
-
padding: var(--space-3);
228
-
background: var(--error-bg);
229
-
border: 1px solid var(--error-border);
230
-
border-radius: var(--radius-md);
231
-
color: var(--error-text);
232
-
margin-bottom: var(--space-4);
233
}
234
235
.audit-list {
-6
frontend/src/routes/DidDocumentEditor.svelte
-6
frontend/src/routes/DidDocumentEditor.svelte
-9
frontend/src/routes/InviteCodes.svelte
-9
frontend/src/routes/InviteCodes.svelte
···
192
margin-bottom: var(--space-7);
193
}
194
195
-
.error {
196
-
padding: var(--space-3);
197
-
background: var(--error-bg);
198
-
border: 1px solid var(--error-border);
199
-
border-radius: var(--radius-md);
200
-
color: var(--error-text);
201
-
margin-bottom: var(--space-4);
202
-
}
203
-
204
.created-code {
205
padding: var(--space-6);
206
background: var(--success-bg);
+10
-8
frontend/src/routes/Migration.svelte
+10
-8
frontend/src/routes/Migration.svelte
···
74
75
if (!hasOAuthCallback) {
76
if (hasPendingMigration()) {
77
-
resumeInfo = getResumeInfo()
78
-
if (resumeInfo) {
79
-
if (resumeInfo.step === 'success') {
80
clearMigrationState()
81
-
resumeInfo = null
82
} else {
83
const stored = loadMigrationState()
84
if (stored && stored.direction === 'inbound') {
85
direction = 'inbound'
86
-
inboundFlow = createInboundMigrationFlow()
87
-
inboundFlow.resumeFromState(stored)
88
}
89
}
90
}
···
94
clearOfflineState()
95
} else {
96
direction = 'offline-inbound'
97
-
offlineFlow = createOfflineInboundMigrationFlow()
98
-
offlineFlow.tryResume()
99
}
100
}
101
}
···
74
75
if (!hasOAuthCallback) {
76
if (hasPendingMigration()) {
77
+
const info = getResumeInfo()
78
+
if (info) {
79
+
if (info.step === 'success') {
80
clearMigrationState()
81
} else {
82
+
resumeInfo = info
83
const stored = loadMigrationState()
84
if (stored && stored.direction === 'inbound') {
85
direction = 'inbound'
86
+
const flow = createInboundMigrationFlow()
87
+
flow.resumeFromState(stored)
88
+
inboundFlow = flow
89
}
90
}
91
}
···
95
clearOfflineState()
96
} else {
97
direction = 'offline-inbound'
98
+
const flow = createOfflineInboundMigrationFlow()
99
+
flow.tryResume()
100
+
offlineFlow = flow
101
}
102
}
103
}
+2
-2
frontend/src/routes/OAuthConsent.svelte
+2
-2
frontend/src/routes/OAuthConsent.svelte
-6
frontend/src/routes/Register.svelte
-6
frontend/src/routes/Register.svelte
-6
frontend/src/routes/RepoExplorer.svelte
-6
frontend/src/routes/RepoExplorer.svelte
-6
frontend/src/routes/Security.svelte
-6
frontend/src/routes/Security.svelte
+1
-2
frontend/src/routes/Settings.svelte
+1
-2
frontend/src/routes/Settings.svelte
-6
frontend/src/routes/TrustedDevices.svelte
-6
frontend/src/routes/TrustedDevices.svelte
+8
frontend/src/styles/migration.css
+8
frontend/src/styles/migration.css
+4
src/lib.rs
+4
src/lib.rs
···
550
.route("/authorize/deny", post(oauth::endpoints::authorize_deny))
551
.route("/authorize/consent", get(oauth::endpoints::consent_get))
552
.route("/authorize/consent", post(oauth::endpoints::consent_post))
553
.route("/delegation/auth", post(oauth::endpoints::delegation_auth))
554
.route(
555
"/delegation/totp",
···
550
.route("/authorize/deny", post(oauth::endpoints::authorize_deny))
551
.route("/authorize/consent", get(oauth::endpoints::consent_get))
552
.route("/authorize/consent", post(oauth::endpoints::consent_post))
553
+
.route(
554
+
"/authorize/redirect",
555
+
get(oauth::endpoints::authorize_redirect),
556
+
)
557
.route("/delegation/auth", post(oauth::endpoints::delegation_auth))
558
.route(
559
"/delegation/totp",
+35
-1
src/util.rs
+35
-1
src/util.rs
···
154
}
155
156
pub fn build_full_url(path: &str) -> String {
157
+
let normalized_path = if !path.starts_with("/xrpc/")
158
+
&& (path.starts_with("/com.atproto.")
159
+
|| path.starts_with("/app.bsky.")
160
+
|| path.starts_with("/_"))
161
+
{
162
+
format!("/xrpc{}", path)
163
+
} else {
164
+
path.to_string()
165
+
};
166
+
format!("{}{}", pds_public_url(), normalized_path)
167
}
168
169
pub fn json_to_ipld(value: &JsonValue) -> Ipld {
···
363
return;
364
}
365
panic!("Failed to find CID link in parsed CBOR");
366
+
}
367
+
368
+
#[test]
369
+
fn test_build_full_url_adds_xrpc_prefix_for_atproto_paths() {
370
+
unsafe { std::env::set_var("PDS_HOSTNAME", "example.com") };
371
+
assert_eq!(
372
+
build_full_url("/com.atproto.server.getSession"),
373
+
"https://example.com/xrpc/com.atproto.server.getSession"
374
+
);
375
+
assert_eq!(
376
+
build_full_url("/app.bsky.feed.getTimeline"),
377
+
"https://example.com/xrpc/app.bsky.feed.getTimeline"
378
+
);
379
+
assert_eq!(
380
+
build_full_url("/_health"),
381
+
"https://example.com/xrpc/_health"
382
+
);
383
+
assert_eq!(
384
+
build_full_url("/xrpc/com.atproto.server.getSession"),
385
+
"https://example.com/xrpc/com.atproto.server.getSession"
386
+
);
387
+
assert_eq!(
388
+
build_full_url("/oauth/token"),
389
+
"https://example.com/oauth/token"
390
+
);
391
}
392
}