-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat multiple accounts and instances #851
Changes from 1 commit
d9fa0bb
6eeef88
fd78fad
9387d95
d250003
144e043
9a61aef
0cf5edd
7c07523
58df0ee
8c77004
c1e5c41
ea494b7
8c7b894
32452ff
0b7a25a
ab9e297
02be0f0
9ac316d
e089e9c
3d36787
cf2ce7d
705647d
2962472
87e88c3
063ac9e
0135a4f
dcea1df
f78b368
2e8f560
b35b4bb
7efedaf
930685c
5bba9cd
3621c3c
64c364e
d36a623
406ef22
fb8e08a
9717830
2fd8f2b
0b817a7
acef728
990557a
33a5680
471fc85
f24abb6
85167e9
069f70c
6d8b6f2
f64000e
c393058
06b2a4b
034d08e
49488a6
469594c
8420eb0
cc78c01
4ae99d5
b5ca8bf
aabddae
dea75b4
5fe0bd2
2db03b5
9116fc0
7ed643e
57984ba
0cf2882
fcb2ddc
3b04fe8
3e054b0
309d764
4641f61
0860867
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,12 +1,82 @@ | ||||||
const inquirer = require("inquirer"); | ||||||
const { Command } = require("commander"); | ||||||
const Client = require("../client"); | ||||||
const { sdkForConsole } = require("../sdks"); | ||||||
const { sdkForConsole, questionGetEndpoint } = require("../sdks"); | ||||||
const { globalConfig, localConfig } = require("../config"); | ||||||
const { actionRunner, success, parseBool, commandDescriptions, error, parse, drawTable } = require("../parser"); | ||||||
{% if sdk.test != "true" %} | ||||||
const { questionsLogin, questionsListFactors, questionsMfaChallenge } = require("../questions"); | ||||||
const { accountUpdateMfaChallenge, accountCreateMfaChallenge, accountGet, accountCreateEmailPasswordSession, accountDeleteSession } = require("./account"); | ||||||
const ID = require("../id"); | ||||||
|
||||||
const DEFAULT_ENDPOINT = 'https://cloud.appwrite.io/v1'; | ||||||
|
||||||
const loginCommand = async ({ selfHosted }) => { | ||||||
const answers = await inquirer.prompt(questionsLogin); | ||||||
const oldCurrent = globalConfig.getCurrentLogin(); | ||||||
const id = ID.unique(); | ||||||
|
||||||
globalConfig.setCurrentLogin(id); | ||||||
globalConfig.addLogin(id, {}); | ||||||
globalConfig.setEmail(answers.email); | ||||||
globalConfig.setEndpoint(DEFAULT_ENDPOINT); | ||||||
|
||||||
if (selfHosted) { | ||||||
const selfHostedAnswers = await inquirer.prompt(questionGetEndpoint); | ||||||
|
||||||
globalConfig.setEndpoint(selfHostedAnswers.endpoint); | ||||||
} | ||||||
|
||||||
let client = await sdkForConsole(false); | ||||||
|
||||||
let account; | ||||||
|
||||||
try { | ||||||
await accountCreateEmailPasswordSession({ | ||||||
email: answers.email, | ||||||
password: answers.password, | ||||||
parseOutput: false, | ||||||
sdk: client | ||||||
}) | ||||||
|
||||||
client.setCookie(globalConfig.getCookie()); | ||||||
|
||||||
account = await accountGet({ | ||||||
sdk: client, | ||||||
parseOutput: false | ||||||
}); | ||||||
} catch (error) { | ||||||
if (error.response === 'user_more_factors_required') { | ||||||
const { factor } = await inquirer.prompt(questionsListFactors); | ||||||
|
||||||
const challenge = await accountCreateMfaChallenge({ | ||||||
factor, | ||||||
parseOutput: false, | ||||||
sdk: client | ||||||
}); | ||||||
|
||||||
const { otp } = await inquirer.prompt(questionsMfaChallenge); | ||||||
|
||||||
await accountUpdateMfaChallenge({ | ||||||
challengeId: challenge.$id, | ||||||
otp, | ||||||
parseOutput: false, | ||||||
sdk: client | ||||||
}); | ||||||
|
||||||
account = await accountGet({ | ||||||
sdk: client, | ||||||
parseOutput: false | ||||||
}); | ||||||
} else { | ||||||
globalConfig.removeLogin(id); | ||||||
globalConfig.setCurrentLogin(oldCurrent); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
throw error; | ||||||
} | ||||||
} | ||||||
|
||||||
success("Signed in as user with ID: " + account.$id); | ||||||
}; | ||||||
|
||||||
const whoami = new Command("whoami") | ||||||
.description(commandDescriptions['whoami']) | ||||||
|
@@ -49,61 +119,74 @@ const whoami = new Command("whoami") | |||||
|
||||||
const login = new Command("login") | ||||||
.description(commandDescriptions['login']) | ||||||
.option(`-sa, --self-hosted`, `Flag for enabling custom endpoint for self hosted instances`) | ||||||
byawitz marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
.configureHelp({ | ||||||
helpWidth: process.stdout.columns || 80 | ||||||
}) | ||||||
.action(actionRunner(loginCommand)); | ||||||
|
||||||
login | ||||||
.command('list') | ||||||
.description("List available logged accounts.") | ||||||
.action(actionRunner(async () => { | ||||||
const answers = await inquirer.prompt(questionsLogin) | ||||||
const logins = globalConfig.getLogins(); | ||||||
const current = globalConfig.getCurrentLogin(); | ||||||
|
||||||
let client = await sdkForConsole(false); | ||||||
const data = [...logins.map((login => { | ||||||
return { | ||||||
'Current': login.id === current ? '*' : '', | ||||||
'ID': login.id, | ||||||
'Endpoint': login.endpoint, | ||||||
'Email': login.email | ||||||
}; | ||||||
}))]; | ||||||
|
||||||
await accountCreateEmailPasswordSession({ | ||||||
email: answers.email, | ||||||
password: answers.password, | ||||||
parseOutput: false, | ||||||
sdk: client | ||||||
}) | ||||||
drawTable(data); | ||||||
|
||||||
client.setCookie(globalConfig.getCookie()); | ||||||
})); | ||||||
|
||||||
let account; | ||||||
login | ||||||
.command('change') | ||||||
.description("Change the current account") | ||||||
.option(`-a, --accountId <accountId>`, `Login ID`) | ||||||
.action(actionRunner(async ({ accountId }) => { | ||||||
const loginIds = globalConfig.getLoginIds(); | ||||||
|
||||||
try { | ||||||
account = await accountGet({ | ||||||
sdk: client, | ||||||
parseOutput: false | ||||||
}); | ||||||
} catch (error) { | ||||||
if (error.response === 'user_more_factors_required') { | ||||||
const { factor } = await inquirer.prompt(questionsListFactors); | ||||||
|
||||||
const challenge = await accountCreateMfaChallenge({ | ||||||
factor, | ||||||
parseOutput: false, | ||||||
sdk: client | ||||||
}); | ||||||
|
||||||
const { otp } = await inquirer.prompt(questionsMfaChallenge); | ||||||
|
||||||
await accountUpdateMfaChallenge({ | ||||||
challengeId: challenge.$id, | ||||||
otp, | ||||||
parseOutput: false, | ||||||
sdk: client | ||||||
}); | ||||||
|
||||||
account = await accountGet({ | ||||||
sdk: client, | ||||||
parseOutput: false | ||||||
}); | ||||||
} else { | ||||||
throw error; | ||||||
} | ||||||
if (!loginIds.includes(accountId)) { | ||||||
throw Error('Login ID not found'); | ||||||
} | ||||||
|
||||||
success("Signed in as user with ID: " + account.$id); | ||||||
globalConfig.setCurrentLogin(accountId); | ||||||
success(`Current account is ${accountId}`); | ||||||
})); | ||||||
|
||||||
login | ||||||
.command('migrate') | ||||||
byawitz marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
.description("Migrate existing login to new scheme") | ||||||
.action(actionRunner(async ({ accountId }) => { | ||||||
const endpoint = globalConfig.getEndpoint(); | ||||||
const cookie = globalConfig.getCookie(); | ||||||
|
||||||
if (endpoint === '' || cookie === '') { | ||||||
throw Error(`Couldn't find any existing account credentials`) | ||||||
} | ||||||
|
||||||
const id = ID.unique(); | ||||||
const data = { | ||||||
endpoint, | ||||||
cookie, | ||||||
email: 'legacy' | ||||||
}; | ||||||
|
||||||
globalConfig.addLogin(id, data); | ||||||
globalConfig.setCurrentLogin(id); | ||||||
globalConfig.delete('endpoint'); | ||||||
globalConfig.delete('cookie'); | ||||||
|
||||||
success(`Account was migrated and it's the current account`); | ||||||
})); | ||||||
|
||||||
|
||||||
const logout = new Command("logout") | ||||||
.description(commandDescriptions['logout']) | ||||||
.configureHelp({ | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -341,14 +341,18 @@ class Local extends Config { | |
class Global extends Config { | ||
static CONFIG_FILE_PATH = ".{{ spec.title|caseLower }}/prefs.json"; | ||
|
||
static PREFERENCE_CURRENT = "current"; | ||
static PREFERENCE_ENDPOINT = "endpoint"; | ||
static PREFERENCE_EMAIL = "email"; | ||
static PREFERENCE_SELF_SIGNED = "selfSigned"; | ||
static PREFERENCE_COOKIE = "cookie"; | ||
static PREFERENCE_PROJECT = "project"; | ||
static PREFERENCE_KEY = "key"; | ||
static PREFERENCE_LOCALE = "locale"; | ||
static PREFERENCE_MODE = "mode"; | ||
|
||
static IGNORE_ATTRIBUTES = [Global.PREFERENCE_CURRENT, Global.PREFERENCE_SELF_SIGNED, Global.PREFERENCE_ENDPOINT, Global.PREFERENCE_COOKIE, Global.PREFERENCE_PROJECT, Global.PREFERENCE_KEY, Global.PREFERENCE_LOCALE, Global.PREFERENCE_MODE]; | ||
|
||
static MODE_ADMIN = "admin"; | ||
static MODE_DEFAULT = "default"; | ||
|
||
|
@@ -359,59 +363,151 @@ class Global extends Config { | |
super(`${homeDir}/${path}`); | ||
} | ||
|
||
getCurrentLogin() { | ||
if (!this.has(Global.PREFERENCE_CURRENT)) { | ||
return ""; | ||
} | ||
return this.get(Global.PREFERENCE_CURRENT); | ||
} | ||
|
||
setCurrentLogin(endpoint) { | ||
this.set(Global.PREFERENCE_CURRENT, endpoint); | ||
} | ||
|
||
getLoginIds() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't this be getSessionIds() ? |
||
return Object.keys(this.data).filter((key) => !Global.IGNORE_ATTRIBUTES.includes(key)); | ||
} | ||
|
||
getLogins() { | ||
const logins = Object.keys(this.data).filter((key) => !Global.IGNORE_ATTRIBUTES.includes(key)) | ||
|
||
return logins.map((login) => { | ||
|
||
return { | ||
id: login, | ||
endpoint: this.data[login][Global.PREFERENCE_ENDPOINT], | ||
email: this.data[login][Global.PREFERENCE_EMAIL] | ||
} | ||
}) | ||
} | ||
|
||
addLogin(login, data) { | ||
this.set(login, data); | ||
} | ||
|
||
removeLogin(login, data) { | ||
this.delete(login); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lets refactor all these method names to use Session / Session And deleteSession / logout |
||
|
||
getEmail() { | ||
if (!this.hasFrom(Global.PREFERENCE_EMAIL)) { | ||
return ""; | ||
} | ||
|
||
return this.getFrom(Global.PREFERENCE_EMAIL); | ||
} | ||
|
||
setEmail(email) { | ||
this.setTo(Global.PREFERENCE_EMAIL, email); | ||
} | ||
|
||
getEndpoint() { | ||
if (!this.has(Global.PREFERENCE_ENDPOINT)) { | ||
if (!this.hasFrom(Global.PREFERENCE_ENDPOINT)) { | ||
return ""; | ||
} | ||
return this.get(Global.PREFERENCE_ENDPOINT); | ||
|
||
return this.getFrom(Global.PREFERENCE_ENDPOINT); | ||
} | ||
|
||
setEndpoint(endpoint) { | ||
this.set(Global.PREFERENCE_ENDPOINT, endpoint); | ||
this.setTo(Global.PREFERENCE_ENDPOINT, endpoint); | ||
} | ||
|
||
getSelfSigned() { | ||
if (!this.has(Global.PREFERENCE_SELF_SIGNED)) { | ||
if (!this.hasFrom(Global.PREFERENCE_SELF_SIGNED)) { | ||
return false; | ||
} | ||
return this.get(Global.PREFERENCE_SELF_SIGNED); | ||
return this.getFrom(Global.PREFERENCE_SELF_SIGNED); | ||
} | ||
|
||
setSelfSigned(selfSigned) { | ||
this.set(Global.PREFERENCE_SELF_SIGNED, selfSigned); | ||
this.setTo(Global.PREFERENCE_SELF_SIGNED, selfSigned); | ||
} | ||
|
||
getCookie() { | ||
if (!this.has(Global.PREFERENCE_COOKIE)) { | ||
if (!this.hasFrom(Global.PREFERENCE_COOKIE)) { | ||
return ""; | ||
} | ||
return this.get(Global.PREFERENCE_COOKIE); | ||
return this.getFrom(Global.PREFERENCE_COOKIE); | ||
} | ||
|
||
setCookie(cookie) { | ||
this.set(Global.PREFERENCE_COOKIE, cookie); | ||
this.setTo(Global.PREFERENCE_COOKIE, cookie); | ||
} | ||
|
||
getProject() { | ||
if (!this.has(Global.PREFERENCE_PROJECT)) { | ||
if (!this.hasFrom(Global.PREFERENCE_PROJECT)) { | ||
return ""; | ||
} | ||
return this.get(Global.PREFERENCE_PROJECT); | ||
return this.getFrom(Global.PREFERENCE_PROJECT); | ||
} | ||
|
||
setProject(project) { | ||
this.set(Global.PREFERENCE_PROJECT, project); | ||
this.setTo(Global.PREFERENCE_PROJECT, project); | ||
} | ||
|
||
getKey() { | ||
if (!this.has(Global.PREFERENCE_KEY)) { | ||
if (!this.hasFrom(Global.PREFERENCE_KEY)) { | ||
return ""; | ||
} | ||
return this.get(Global.PREFERENCE_KEY); | ||
} | ||
|
||
setKey(key) { | ||
this.set(Global.PREFERENCE_KEY, key); | ||
this.setTo(Global.PREFERENCE_KEY, key); | ||
} | ||
|
||
hasFrom(key) { | ||
try { | ||
const current = this.getCurrentLogin(); | ||
|
||
if (current) { | ||
const config = this.get(current); | ||
|
||
return config[key] !== undefined; | ||
} | ||
} catch { | ||
return this.has(key); | ||
} | ||
} | ||
|
||
getFrom(key) { | ||
try { | ||
const current = this.getCurrentLogin(); | ||
|
||
if (current) { | ||
const config = this.get(current); | ||
|
||
return config[key]; | ||
} | ||
} catch { | ||
return this.get(key); | ||
} | ||
} | ||
|
||
setTo(key, value) { | ||
try { | ||
const current = this.getCurrentLogin(); | ||
|
||
if (current) { | ||
const config = this.get(current); | ||
|
||
config[key] = value; | ||
this.write(); | ||
} | ||
} catch { | ||
this.set(key, value); | ||
} | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.