bitty-tui 0.0.13 → 0.0.15
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.
- package/dist/cli.js +5 -1
- package/dist/clients/bw.d.ts +1 -0
- package/dist/clients/bw.js +15 -3
- package/dist/dashboard/DashboardView.js +1 -0
- package/dist/login/LoginView.js +52 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5,9 +5,13 @@ import App from "./app.js";
|
|
|
5
5
|
import { StatusMessageProvider } from "./hooks/status-message.js";
|
|
6
6
|
import { readPackageUpSync } from "read-package-up";
|
|
7
7
|
import { art } from "./theme/art.js";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
8
10
|
const args = process.argv.slice(2);
|
|
9
11
|
if (args.includes("--version") || args.includes("-v")) {
|
|
10
|
-
const
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
const pkg = readPackageUpSync({ cwd: __dirname });
|
|
11
15
|
console.log(pkg?.packageJson.version ?? "unknown");
|
|
12
16
|
process.exit(0);
|
|
13
17
|
}
|
package/dist/clients/bw.d.ts
CHANGED
package/dist/clients/bw.js
CHANGED
|
@@ -101,9 +101,12 @@ export var KeyType;
|
|
|
101
101
|
export const TwoFactorProvider = {
|
|
102
102
|
"0": "Authenticator",
|
|
103
103
|
"1": "Email",
|
|
104
|
-
"2": "
|
|
104
|
+
"2": "Duo",
|
|
105
105
|
"3": "Yubikey",
|
|
106
|
-
"4": "
|
|
106
|
+
"4": "U2f",
|
|
107
|
+
"6": "Org Duo",
|
|
108
|
+
"7": "Fido2",
|
|
109
|
+
"8": "Recovery Code",
|
|
107
110
|
};
|
|
108
111
|
export var KdfType;
|
|
109
112
|
(function (KdfType) {
|
|
@@ -449,7 +452,7 @@ export class Client {
|
|
|
449
452
|
this.orgKeys = {};
|
|
450
453
|
}
|
|
451
454
|
async sendEmailMfaCode(email) {
|
|
452
|
-
fetch(
|
|
455
|
+
fetch(`${this.apiUrl}/two-factor/send-email-login`, {
|
|
453
456
|
method: "POST",
|
|
454
457
|
headers: {
|
|
455
458
|
"Content-Type": "application/json",
|
|
@@ -798,4 +801,13 @@ export class Client {
|
|
|
798
801
|
}
|
|
799
802
|
return ret;
|
|
800
803
|
}
|
|
804
|
+
logout() {
|
|
805
|
+
this.token = null;
|
|
806
|
+
this.refreshToken = null;
|
|
807
|
+
this.tokenExpiration = null;
|
|
808
|
+
this.keys = {};
|
|
809
|
+
this.orgKeys = {};
|
|
810
|
+
this.decryptedSyncCache = null;
|
|
811
|
+
this.syncCache = null;
|
|
812
|
+
}
|
|
801
813
|
}
|
|
@@ -42,6 +42,7 @@ export function DashboardView({ onLogout }) {
|
|
|
42
42
|
}, [listSelected, filteredCiphers]);
|
|
43
43
|
const selectedCipher = detailMode === "new" ? editedCipher : filteredCiphers[listIndex];
|
|
44
44
|
const logout = async () => {
|
|
45
|
+
bwClient.logout();
|
|
45
46
|
await clearConfig();
|
|
46
47
|
onLogout();
|
|
47
48
|
};
|
package/dist/login/LoginView.js
CHANGED
|
@@ -16,10 +16,17 @@ export function LoginView({ onLogin }) {
|
|
|
16
16
|
const [password, setPassword] = useState("");
|
|
17
17
|
const [mfaParams, setMfaParams] = useState(null);
|
|
18
18
|
const [askMfa, setAskMfa] = useState(null);
|
|
19
|
+
const [mfaProviderData, setMfaProviderData] = useState(null);
|
|
19
20
|
const [rememberMe, setRememberMe] = useState(false);
|
|
21
|
+
const [resendTimeout, setResendTimeout] = useState(0);
|
|
20
22
|
const { stdout } = useStdout();
|
|
21
23
|
const { focusNext, focusPrevious } = useFocusManager();
|
|
22
24
|
const { statusMessage, statusMessageColor, showStatusMessage } = useStatusMessage();
|
|
25
|
+
const getProviderLabel = (provider) => TwoFactorProvider[String(provider)] ?? `Provider ${provider}`;
|
|
26
|
+
const getProviderData = (provider) => mfaProviderData?.[String(provider)] ?? null;
|
|
27
|
+
const isEmailProvider = (provider) => String(provider) === "1";
|
|
28
|
+
const isDuoProvider = (provider) => String(provider) === "2" || String(provider) === "6";
|
|
29
|
+
const isWebAuthnProvider = (provider) => String(provider) === "7";
|
|
23
30
|
useInput(async (_, key) => {
|
|
24
31
|
if (key.upArrow) {
|
|
25
32
|
focusPrevious();
|
|
@@ -47,14 +54,29 @@ export function LoginView({ onLogin }) {
|
|
|
47
54
|
catch (e) {
|
|
48
55
|
if (e instanceof FetchError) {
|
|
49
56
|
const data = e.json();
|
|
57
|
+
if (data.TwoFactorProviders2) {
|
|
58
|
+
setMfaProviderData(data.TwoFactorProviders2);
|
|
59
|
+
}
|
|
50
60
|
if (data.TwoFactorProviders) {
|
|
51
|
-
|
|
61
|
+
const providers = data.TwoFactorProviders;
|
|
62
|
+
if (providers.length === 1) {
|
|
52
63
|
setMfaParams({
|
|
53
|
-
twoFactorProvider:
|
|
64
|
+
twoFactorProvider: providers[0],
|
|
54
65
|
});
|
|
55
66
|
}
|
|
56
|
-
else if (
|
|
57
|
-
setAskMfa(
|
|
67
|
+
else if (providers.length > 1) {
|
|
68
|
+
setAskMfa(providers);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (data.TwoFactorProviders2) {
|
|
72
|
+
const providers = Object.keys(data.TwoFactorProviders2);
|
|
73
|
+
if (providers.length === 1) {
|
|
74
|
+
setMfaParams({
|
|
75
|
+
twoFactorProvider: providers[0],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else if (providers.length > 1) {
|
|
79
|
+
setAskMfa(providers);
|
|
58
80
|
}
|
|
59
81
|
}
|
|
60
82
|
}
|
|
@@ -93,8 +115,20 @@ export function LoginView({ onLogin }) {
|
|
|
93
115
|
}
|
|
94
116
|
})();
|
|
95
117
|
}, []);
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
let interval;
|
|
120
|
+
if (resendTimeout > 0) {
|
|
121
|
+
interval = setInterval(() => {
|
|
122
|
+
setResendTimeout((t) => t - 1);
|
|
123
|
+
}, 1000);
|
|
124
|
+
}
|
|
125
|
+
return () => {
|
|
126
|
+
if (interval)
|
|
127
|
+
clearInterval(interval);
|
|
128
|
+
};
|
|
129
|
+
}, [resendTimeout]);
|
|
96
130
|
return (_jsxs(Box, { flexDirection: "column", alignItems: "center", padding: 1, flexGrow: 1, minHeight: stdout.rows - 2, children: [_jsx(Box, { marginBottom: 2, children: _jsx(Text, { color: primary, children: art }) }), loading ? (_jsx(Text, { children: "Loading..." })) : askMfa ? (_jsx(Box, { flexDirection: "column", width: "50%", children: Object.values(askMfa).map((provider) => (_jsx(Button, { autoFocus: true, onClick: () => {
|
|
97
|
-
if (provider
|
|
131
|
+
if (isEmailProvider(provider) &&
|
|
98
132
|
(Object.values(askMfa).length > 1 ||
|
|
99
133
|
!bwClient.isVaultWarden())) {
|
|
100
134
|
bwClient.sendEmailMfaCode(email);
|
|
@@ -104,7 +138,19 @@ export function LoginView({ onLogin }) {
|
|
|
104
138
|
twoFactorProvider: provider,
|
|
105
139
|
}));
|
|
106
140
|
setAskMfa(null);
|
|
107
|
-
}, children:
|
|
141
|
+
}, children: getProviderLabel(provider) }, provider))) })) : mfaParams && mfaParams.twoFactorProvider ? (_jsxs(Box, { flexDirection: "column", width: "50%", children: [isDuoProvider(mfaParams.twoFactorProvider) && (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { children: "Open the Duo URL in a browser and approve the request." }), _jsx(Text, { children: "Then paste the `code` and `state` from the final URL as `code|state`." }), getProviderData(mfaParams.twoFactorProvider)?.AuthUrl && (_jsxs(Text, { children: ["Auth URL:", " ", getProviderData(mfaParams.twoFactorProvider).AuthUrl] }))] })), isWebAuthnProvider(mfaParams.twoFactorProvider) && (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: _jsx(Text, { children: "Use your FIDO2/WebAuthn security key to generate a response, then paste it here." }) })), _jsx(TextInput, { autoFocus: true, placeholder: `Enter your ${getProviderLabel(mfaParams.twoFactorProvider)} ${isWebAuthnProvider(mfaParams.twoFactorProvider)
|
|
142
|
+
? "response"
|
|
143
|
+
: "code"}`, value: mfaParams.twoFactorToken || "", onChange: (value) => setMfaParams((p) => ({ ...p, twoFactorToken: value })), onSubmit: () => handleLogin() }), isEmailProvider(mfaParams.twoFactorProvider) && (_jsx(Button, { marginTop: 1, isActive: resendTimeout === 0, onClick: () => {
|
|
144
|
+
bwClient
|
|
145
|
+
.sendEmailMfaCode(email)
|
|
146
|
+
.then(() => {
|
|
147
|
+
showStatusMessage("Sent new MFA code to your email.", "success");
|
|
148
|
+
})
|
|
149
|
+
.catch(() => {
|
|
150
|
+
showStatusMessage("Failed to resend MFA code.", "error");
|
|
151
|
+
});
|
|
152
|
+
setResendTimeout(30);
|
|
153
|
+
}, children: "Resend Code" }))] })) : (_jsxs(Box, { flexDirection: "column", width: "50%", children: [_jsx(TextInput, { placeholder: "Server URL", value: url, onChange: setUrl }), _jsx(TextInput, { autoFocus: true, placeholder: "Email address", value: email, onChange: setEmail }), _jsx(TextInput, { placeholder: "Master password", value: password, onChange: setPassword, onSubmit: () => {
|
|
108
154
|
if (email?.length && password?.length) {
|
|
109
155
|
handleLogin();
|
|
110
156
|
}
|