Skip to content

Commit d32847d

Browse files
committed
initila work for redirect to obsidian uri scheme
1 parent 699f35e commit d32847d

6 files changed

Lines changed: 226 additions & 144 deletions

File tree

.github/workflows/deploy_static.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ jobs:
3636
uses: actions/configure-pages@v5
3737
- name: Prepare static files
3838
run: |
39-
mkdir -p _site/home/treethought/Pictures/Screenshot_20260205_205803.png
39+
mkdir -p _site
4040
cp client-metadata.json _site/
41+
cp oauth-callback.html _site/
4142
- name: Upload artifact
4243
uses: actions/upload-pages-artifact@v3
4344
with:

client-metadata.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"client_id": "https://treethought.github.io/obsidian-atmosphere/client-metadata.json",
33
"client_name": "obsidian-atmosphere",
4-
"client_uri": "https://example.com",
4+
"client_uri": "https://treethought.github.io/obsidian-atmosphere",
55
"redirect_uris": [
6-
"http://127.0.0.1/callback"
6+
"https://treethought.github.io/obsidian-atmosphere/oauth-callback.html"
77
],
8-
"scope": "atproto transition:generic",
8+
"scope": "atproto include:at.margin.authFull repo:site.standard.document repo:network.cosmik.card repo:network.cosmik.collection repo:network.cosmik.collectionLink",
99
"grant_types": ["authorization_code", "refresh_token"],
1010
"response_types": ["code"],
1111
"token_endpoint_auth_method": "none",

oauth-callback.html

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Atmosphere OAuth - Redirecting...</title>
7+
<style>
8+
* {
9+
margin: 0;
10+
padding: 0;
11+
box-sizing: border-box;
12+
}
13+
body {
14+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
15+
display: flex;
16+
align-items: center;
17+
justify-content: center;
18+
min-height: 100vh;
19+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
20+
padding: 1rem;
21+
}
22+
.container {
23+
text-align: center;
24+
padding: 3rem 2rem;
25+
background: white;
26+
border-radius: 16px;
27+
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
28+
max-width: 500px;
29+
width: 100%;
30+
}
31+
h1 {
32+
color: #667eea;
33+
margin: 0 0 1rem 0;
34+
font-size: 1.75rem;
35+
font-weight: 600;
36+
}
37+
.spinner {
38+
margin: 2rem auto;
39+
width: 50px;
40+
height: 50px;
41+
border: 4px solid #f3f3f3;
42+
border-top: 4px solid #667eea;
43+
border-radius: 50%;
44+
animation: spin 1s linear infinite;
45+
}
46+
@keyframes spin {
47+
0% { transform: rotate(0deg); }
48+
100% { transform: rotate(360deg); }
49+
}
50+
p {
51+
color: #6b7280;
52+
margin: 1rem 0;
53+
line-height: 1.6;
54+
}
55+
.manual-link {
56+
margin-top: 2rem;
57+
padding: 1rem;
58+
background: #f9fafb;
59+
border-radius: 8px;
60+
border: 1px solid #e5e7eb;
61+
display: none;
62+
}
63+
.manual-link.show {
64+
display: block;
65+
}
66+
.link-text {
67+
word-break: break-all;
68+
font-family: monospace;
69+
font-size: 0.85rem;
70+
color: #374151;
71+
padding: 0.5rem;
72+
background: white;
73+
border-radius: 4px;
74+
margin-top: 0.5rem;
75+
}
76+
button {
77+
margin-top: 1rem;
78+
padding: 0.75rem 1.5rem;
79+
background: #667eea;
80+
color: white;
81+
border: none;
82+
border-radius: 8px;
83+
font-size: 1rem;
84+
font-weight: 500;
85+
cursor: pointer;
86+
transition: background 0.2s;
87+
}
88+
button:hover {
89+
background: #5568d3;
90+
}
91+
</style>
92+
</head>
93+
<body>
94+
<div class="container">
95+
<h1>✅ Authentication Successful!</h1>
96+
<div class="spinner"></div>
97+
<p id="status">Redirecting to Obsidian...</p>
98+
<div class="manual-link" id="manual-link">
99+
<p>If Obsidian doesn't open automatically:</p>
100+
<p style="font-size: 0.9rem; margin-bottom: 0.5rem;">1. Copy the link below</p>
101+
<div class="link-text" id="link-text"></div>
102+
<button onclick="copyLink()">Copy Link</button>
103+
<p style="font-size: 0.9rem; margin-top: 1rem;">2. Open Obsidian and paste it in your browser</p>
104+
</div>
105+
</div>
106+
107+
<script>
108+
(function() {
109+
try {
110+
// Extract OAuth parameters from URL
111+
const params = new URLSearchParams(window.location.search);
112+
113+
// Build Obsidian URI with all OAuth callback parameters
114+
const obsidianUri = `obsidian://atmosphere-oauth?${params.toString()}`;
115+
116+
// Store the URI for manual copy
117+
document.getElementById('link-text').textContent = obsidianUri;
118+
119+
// Attempt automatic redirect
120+
window.location.href = obsidianUri;
121+
122+
// Show manual instructions after a delay if redirect didn't work
123+
setTimeout(function() {
124+
document.getElementById('status').textContent = 'Having trouble redirecting?';
125+
document.getElementById('manual-link').classList.add('show');
126+
}, 2000);
127+
128+
} catch (error) {
129+
console.error('Redirect error:', error);
130+
document.getElementById('status').textContent = 'An error occurred during redirect';
131+
document.getElementById('manual-link').classList.add('show');
132+
}
133+
})();
134+
135+
function copyLink() {
136+
const linkText = document.getElementById('link-text').textContent;
137+
navigator.clipboard.writeText(linkText).then(function() {
138+
const btn = event.target;
139+
btn.textContent = '✓ Copied!';
140+
setTimeout(function() {
141+
btn.textContent = 'Copy Link';
142+
}, 2000);
143+
}).catch(function(err) {
144+
console.error('Failed to copy:', err);
145+
alert('Failed to copy. Please select and copy the link manually.');
146+
});
147+
}
148+
</script>
149+
</body>
150+
</html>

src/lib/client.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ export class ATClient extends Client {
3838
async getActor(identifier: string): Promise<ResolvedActor> {
3939
return this.hh.getActor(identifier);
4040
}
41+
42+
handleOAuthCallback(params: URLSearchParams): void {
43+
this.hh.handleOAuthCallback(params);
44+
}
4145
}
4246

4347
/**
@@ -67,6 +71,10 @@ export class Handler implements FetchHandlerObject {
6771
this.session = undefined;
6872
}
6973

74+
handleOAuthCallback(params: URLSearchParams): void {
75+
this.oauth.handleCallback(params);
76+
}
77+
7078
async getActor(identifier: string): Promise<ResolvedActor> {
7179
const key = `actor:${identifier}`;
7280
const cached = this.cache.get<ResolvedActor>(key);

0 commit comments

Comments
 (0)