0.10.6: Sync sign-in comes back through 127.0.0.1
Browsers open a vscode:// link only after a click on the page. With a live identity provider session the sign-in ran without one, so the editor kept waiting. On the desktop the browser now returns to a one-off listener on 127.0.0.1; remote and web editors keep the URI handler.
This commit is contained in:
1 parent
b54304fef8
commit
95c6e60199
4 files changed
+43
-6
No files matched your search
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.10.6 — 2026-11-08
|
||||||
|
|
||||||
|
- **Sync sign-in comes back by itself.** The browser now returns the sign-in to a one-off port on this machine (`127.0.0.1`) instead of a `vscode://` link. Browsers open such links only after a click, so when you were already signed in to the identity provider the editor kept waiting. Remote and web editors still use the link.
|
||||||
|
|
||||||
## 0.10.5 — 2026-11-08
|
## 0.10.5 — 2026-11-08
|
||||||
|
|
||||||
- **Sync button fixed.** It is now an icon only (a cloud; green with a broadcast icon once the model is shared), the same size on every page and theme. On a diagram it sits in the toolbar after **Export** instead of over it; in narrow windows and high contrast themes it no longer shrinks or loses its colour.
|
- **Sync button fixed.** It is now an icon only (a cloud; green with a broadcast icon once the model is shared), the same size on every page and theme. On a diagram it sits in the toolbar after **Export** instead of over it; in narrow windows and high contrast themes it no longer shrinks or loses its colour.
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "archify-vscode-ext",
|
"name": "archify-vscode-ext",
|
||||||
"version": "0.10.5",
|
"version": "0.10.6",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "archify-vscode-ext",
|
"name": "archify-vscode-ext",
|
||||||
"version": "0.10.5",
|
"version": "0.10.6",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.20.4",
|
"@codemirror/autocomplete": "^6.20.4",
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
"name": "archify-vscode-ext",
|
"name": "archify-vscode-ext",
|
||||||
"displayName": "Archify Diagram Viewer",
|
"displayName": "Archify Diagram Viewer",
|
||||||
"description": "Archify diagrams in VS Code. Write diagrams as .archify files in YAML: they open as the interactive diagram, with live updates, validation, templates and completion. Also previews Archify's own JSON files (*.architecture.json, …) and opens rendered Archify HTML.",
|
"description": "Archify diagrams in VS Code. Write diagrams as .archify files in YAML: they open as the interactive diagram, with live updates, validation, templates and completion. Also previews Archify's own JSON files (*.architecture.json, …) and opens rendered Archify HTML.",
|
||||||
"version": "0.10.5",
|
"version": "0.10.6",
|
||||||
"publisher": "root-at-skic",
|
"publisher": "root-at-skic",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"sponsor": {
|
"sponsor": {
|
||||||
|
|||||||
+36
-3
@@ -1,4 +1,5 @@
|
|||||||
import * as crypto from 'node:crypto';
|
import * as crypto from 'node:crypto';
|
||||||
|
import * as http from 'node:http';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { SyncApi, SyncApiError } from './api';
|
import { SyncApi, SyncApiError } from './api';
|
||||||
import { Account, TokenResponse } from './protocol';
|
import { Account, TokenResponse } from './protocol';
|
||||||
@@ -100,8 +101,13 @@ export class SyncAuth implements vscode.AuthenticationProvider, vscode.Disposabl
|
|||||||
const verifier = crypto.randomBytes(32).toString('base64url');
|
const verifier = crypto.randomBytes(32).toString('base64url');
|
||||||
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
|
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
|
||||||
const state = crypto.randomBytes(16).toString('base64url');
|
const state = crypto.randomBytes(16).toString('base64url');
|
||||||
const callback = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://${this.context.extension.id}/auth`));
|
// On the desktop the browser comes back to a port on this machine: no
|
||||||
const redirectUri = callback.toString(true);
|
// click needed, and it reaches this window. Remote and web editors use
|
||||||
|
// the extension's URI handler (vscode://…/auth) instead.
|
||||||
|
const loopback = vscode.env.remoteName === undefined && vscode.env.uiKind === vscode.UIKind.Desktop ? await this.listen().catch(() => undefined) : undefined;
|
||||||
|
const redirectUri = loopback
|
||||||
|
? `http://127.0.0.1:${loopback.port}/auth`
|
||||||
|
: (await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://${this.context.extension.id}/auth`))).toString(true);
|
||||||
const query = new URLSearchParams({
|
const query = new URLSearchParams({
|
||||||
response_type: 'code',
|
response_type: 'code',
|
||||||
redirect_uri: redirectUri,
|
redirect_uri: redirectUri,
|
||||||
@@ -119,6 +125,7 @@ export class SyncAuth implements vscode.AuthenticationProvider, vscode.Disposabl
|
|||||||
const done = () => {
|
const done = () => {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
this.pending.delete(state);
|
this.pending.delete(state);
|
||||||
|
loopback?.close();
|
||||||
};
|
};
|
||||||
this.pending.set(state, {
|
this.pending.set(state, {
|
||||||
resolve: (c) => (done(), resolve(c)),
|
resolve: (c) => (done(), resolve(c)),
|
||||||
@@ -137,9 +144,35 @@ export class SyncAuth implements vscode.AuthenticationProvider, vscode.Disposabl
|
|||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A one-off HTTP listener on 127.0.0.1 for the browser's way back; closed when the sign-in ends. */
|
||||||
|
private listen(): Promise<{ port: number; close: () => void }> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const server = http.createServer((req, res) => {
|
||||||
|
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
||||||
|
const known = url.pathname === '/auth' && this.pending.has(url.searchParams.get('state') ?? '');
|
||||||
|
res.writeHead(known ? 200 : 404, { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-store' });
|
||||||
|
res.end(
|
||||||
|
known
|
||||||
|
? '<!doctype html><meta charset="utf-8"><title>Archify Sync</title><body style="font:15px system-ui;margin:48px auto;max-width:420px"><h2>Signed in</h2><p>You can close this tab and go back to the editor.</p></body>'
|
||||||
|
: 'Not found',
|
||||||
|
);
|
||||||
|
if (known) this.completeSignIn(url.searchParams);
|
||||||
|
});
|
||||||
|
server.once('error', reject);
|
||||||
|
server.listen(0, '127.0.0.1', () => {
|
||||||
|
const address = server.address();
|
||||||
|
if (!address || typeof address === 'string') return reject(new Error('no port'));
|
||||||
|
resolve({ port: address.port, close: () => server.close() });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** The browser came back: `…/auth?code=&state=`. */
|
/** The browser came back: `…/auth?code=&state=`. */
|
||||||
handleAuthUri(uri: vscode.Uri): void {
|
handleAuthUri(uri: vscode.Uri): void {
|
||||||
const query = new URLSearchParams(uri.query);
|
this.completeSignIn(new URLSearchParams(uri.query));
|
||||||
|
}
|
||||||
|
|
||||||
|
private completeSignIn(query: URLSearchParams): void {
|
||||||
const state = query.get('state') ?? '';
|
const state = query.get('state') ?? '';
|
||||||
const code = query.get('code');
|
const code = query.get('code');
|
||||||
const pending = this.pending.get(state);
|
const pending = this.pending.get(state);
|
||||||
|
|||||||
Reference in new issue
Block a user