feat: save session token to config

main
spacemeowx2 2022-10-18 21:16:51 +08:00
parent 8fcb758c97
commit dd55ec6072
6 changed files with 101 additions and 8 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.json
.vscode/

View File

@ -3,4 +3,6 @@ export {
CookieJar,
wrapFetch,
} from "https://deno.land/x/another_cookiejar@v4.1.4/mod.ts";
export * as base64 from "https://deno.land/std@0.95.0/encoding/base64.ts";
export * as base64 from "https://deno.land/std@0.160.0/encoding/base64.ts";
export * as flags from "https://deno.land/std@0.160.0/flags/mod.ts";
export * as io from "https://deno.land/std@0.160.0/io/mod.ts";

View File

@ -1,6 +1,6 @@
import { CookieJar, wrapFetch } from "./deps.ts";
import { LoginState } from "./state.ts";
import { urlBase64Encode } from "./utils.ts";
import { readline, urlBase64Encode } from "./utils.ts";
const NSOAPP_VERSION = "2.3.1";
@ -95,10 +95,11 @@ export async function loginManually(): Promise<LoginState> {
console.log("Navigate to this URL in your browser:");
console.log(res.url);
const login = prompt(
'Log in, right click the "Select this account" button, copy the link address, and paste it below:\n',
console.log(
'Log in, right click the "Select this account" button, copy the link address, and paste it below:',
);
const login = await readline();
if (!login) {
throw new Error("No login URL provided");
}

77
s3si.ts
View File

@ -1,4 +1,77 @@
import { loginManually } from "./iksm.ts";
import { flags } from "./deps.ts";
import { DEFAULT_STATE, State } from "./state.ts";
const state = await loginManually();
console.log(state);
type Opts = {
configPath: string;
help?: boolean;
};
const DEFAULT_OPTS = {
configPath: "./config.json",
help: false,
};
class App {
state: State = DEFAULT_STATE;
constructor(public opts: Opts) {
if (this.opts.help) {
console.log(
`Usage: deno run --allow-net --allow-read --allow-write ${Deno.mainModule} [options]
Options:
--config-path <path> Path to config file (default: ./config.json)
--help Show this help message and exit`,
);
Deno.exit(0);
}
}
async writeState() {
const encoder = new TextEncoder();
const data = encoder.encode(JSON.stringify(this.state, undefined, 2));
await Deno.writeFile(this.opts.configPath + ".swap", data);
await Deno.rename(this.opts.configPath + ".swap", this.opts.configPath);
}
async readState() {
const decoder = new TextDecoder();
try {
const data = await Deno.readFile(this.opts.configPath);
const json = JSON.parse(decoder.decode(data));
this.state = json;
} catch (e) {
console.warn(
`Failed to read config file, create new config file. (${e})`,
);
await this.writeState();
}
}
async run() {
await this.readState();
if (!this.state.loginState?.sessionToken) {
const { sessionToken } = await loginManually();
this.state.loginState = {
...this.state.loginState,
sessionToken,
};
await this.writeState();
}
}
}
const parseArgs = (args: string[]) => {
const parsed = flags.parse(args, {
string: ["configPath"],
boolean: ["help"],
alias: {
"help": "h",
"configPath": ["c", "config-path"],
},
});
return parsed;
};
const app = new App({
...DEFAULT_OPTS,
...parseArgs(Deno.args),
});
await app.run();

View File

@ -1,3 +1,8 @@
export type LoginState = {
sessionToken: string;
};
export type State = {
loginState?: LoginState;
};
export const DEFAULT_STATE: State = {};

View File

@ -1,4 +1,6 @@
import { base64 } from "./deps.ts";
import { base64, io } from "./deps.ts";
const stdinLines = io.readLines(Deno.stdin);
export function urlBase64Encode(data: ArrayBuffer) {
return base64.encode(data)
@ -14,3 +16,11 @@ export function urlBase64Decode(data: string) {
.replaceAll("-", "/"),
);
}
export async function readline() {
for await (const line of stdinLines) {
if (line !== "") {
return line;
}
}
}