@profullstack/qryptchat 0.1.0 → 0.1.1
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.
|
@@ -1049,10 +1049,32 @@ var TIMEOUT_MS = 5 * 60 * 1000;
|
|
|
1049
1049
|
var PAGE = (title, body) => `<!doctype html><meta charset="utf-8"><title>${title}</title>
|
|
1050
1050
|
<style>body{font:16px system-ui,sans-serif;display:grid;place-items:center;min-height:90vh;background:#0b0d12;color:#e6e8ee}main{max-width:28rem;text-align:center}</style>
|
|
1051
1051
|
<main><h1>${title}</h1><p>${body}</p></main>`;
|
|
1052
|
+
function isRemote({ platform = process.platform, env = process.env } = {}) {
|
|
1053
|
+
if (env.QC_NO_BROWSER)
|
|
1054
|
+
return true;
|
|
1055
|
+
return !!(env.SSH_CONNECTION || env.SSH_TTY) && !env.DISPLAY && !env.WAYLAND_DISPLAY && platform !== "darwin" && platform !== "win32";
|
|
1056
|
+
}
|
|
1057
|
+
function parsePasted(input, state) {
|
|
1058
|
+
const text = String(input || "").trim();
|
|
1059
|
+
if (!text)
|
|
1060
|
+
return null;
|
|
1061
|
+
if (/^https?:\/\//i.test(text)) {
|
|
1062
|
+
let url;
|
|
1063
|
+
try {
|
|
1064
|
+
url = new URL(text);
|
|
1065
|
+
} catch {
|
|
1066
|
+
return null;
|
|
1067
|
+
}
|
|
1068
|
+
const got = url.searchParams.get("state");
|
|
1069
|
+
if (got && got !== state)
|
|
1070
|
+
throw new Error("That link belongs to a different login. Run qc login again.");
|
|
1071
|
+
return url.searchParams.get("code");
|
|
1072
|
+
}
|
|
1073
|
+
return /^[A-Za-z0-9_-]{20,}$/.test(text) ? text : null;
|
|
1074
|
+
}
|
|
1052
1075
|
function openBrowser(url, { platform = process.platform, env = process.env } = {}) {
|
|
1053
|
-
if (
|
|
1076
|
+
if (isRemote({ platform, env }))
|
|
1054
1077
|
return false;
|
|
1055
|
-
}
|
|
1056
1078
|
const [cmd, args] = platform === "darwin" ? ["open", [url]] : platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
1057
1079
|
try {
|
|
1058
1080
|
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
@@ -1102,7 +1124,8 @@ async function login(options = {}) {
|
|
|
1102
1124
|
const ephemeral = await ephemeralKeypair();
|
|
1103
1125
|
let server;
|
|
1104
1126
|
let redirectUri = "oob";
|
|
1105
|
-
|
|
1127
|
+
const oob = options.oob || isRemote({ env });
|
|
1128
|
+
if (!oob) {
|
|
1106
1129
|
server = createServer();
|
|
1107
1130
|
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
1108
1131
|
redirectUri = `http://127.0.0.1:${server.address().port}/callback`;
|
|
@@ -1124,20 +1147,44 @@ async function login(options = {}) {
|
|
|
1124
1147
|
print(` Confirmation code: ${match}`);
|
|
1125
1148
|
print(" Check that the browser shows the same code before you approve.");
|
|
1126
1149
|
print("");
|
|
1127
|
-
const opened = !
|
|
1150
|
+
const opened = !oob && openBrowser(url.toString(), { env });
|
|
1128
1151
|
print(opened ? " Opened your browser. If it did not, open:" : " Open this link in a browser where you are signed in to qrypt.chat:");
|
|
1129
1152
|
print(` ${url.toString()}`);
|
|
1130
1153
|
print("");
|
|
1131
1154
|
let code;
|
|
1155
|
+
let rl;
|
|
1132
1156
|
try {
|
|
1133
1157
|
if (server) {
|
|
1134
|
-
|
|
1158
|
+
const waits = [waitForCallback(server, state)];
|
|
1159
|
+
if (process.stdin.isTTY) {
|
|
1160
|
+
rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
1161
|
+
waits.push((async () => {
|
|
1162
|
+
for (;; ) {
|
|
1163
|
+
let line;
|
|
1164
|
+
try {
|
|
1165
|
+
line = await rl.question(" Waiting for the browser… or paste the URL it ended up on: ");
|
|
1166
|
+
} catch {
|
|
1167
|
+
return new Promise(() => {});
|
|
1168
|
+
}
|
|
1169
|
+
const pasted = parsePasted(line, state);
|
|
1170
|
+
if (pasted)
|
|
1171
|
+
return pasted;
|
|
1172
|
+
print(" That is not a qc login code or callback URL.");
|
|
1173
|
+
}
|
|
1174
|
+
})());
|
|
1175
|
+
}
|
|
1176
|
+
code = await Promise.race(waits);
|
|
1135
1177
|
} else {
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1178
|
+
rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
1179
|
+
for (;; ) {
|
|
1180
|
+
code = parsePasted(await rl.question(" Paste the code (or the URL) from the browser: "), state);
|
|
1181
|
+
if (code)
|
|
1182
|
+
break;
|
|
1183
|
+
print(" That is not a qc login code.");
|
|
1184
|
+
}
|
|
1139
1185
|
}
|
|
1140
1186
|
} finally {
|
|
1187
|
+
rl?.close();
|
|
1141
1188
|
server?.close();
|
|
1142
1189
|
}
|
|
1143
1190
|
if (!code)
|
package/dist/commands.js
CHANGED
package/dist/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@profullstack/qryptchat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "qc: qrypt.chat in your terminal. A full-screen end-to-end encrypted chat client (ML-KEM-1024), plus a scriptable CLI and an MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|