diff --git a/net/server/internal/api_getAccountStatus.go b/net/server/internal/api_getAccountStatus.go index 0d30c1c4..b15187ad 100644 --- a/net/server/internal/api_getAccountStatus.go +++ b/net/server/internal/api_getAccountStatus.go @@ -35,6 +35,7 @@ func GetAccountStatus(w http.ResponseWriter, r *http.Request) { status.Disabled = account.Disabled status.ForwardingAddress = account.Forward status.Searchable = account.Searchable + status.MFAEnabled = account.MFAEnabled && account.MFAConfirmed status.Sealable = true status.EnableIce = getBoolConfigValue(CNFEnableIce, false) status.AllowUnsealed = getBoolConfigValue(CNFAllowUnsealed, false) diff --git a/net/server/internal/models.go b/net/server/internal/models.go index 9bbdc34a..82ace1fc 100644 --- a/net/server/internal/models.go +++ b/net/server/internal/models.go @@ -35,6 +35,8 @@ type AccountStatus struct { Searchable bool `json:"searchable"` + MFAEnabled bool `json:"mfaEnabled"` + PushEnabled bool `json:"pushEnabled"` Sealable bool `json:"sealable"` diff --git a/net/web/src/api/addAccountMFA.js b/net/web/src/api/addAccountMFA.js new file mode 100644 index 00000000..fbc1c81f --- /dev/null +++ b/net/web/src/api/addAccountMFA.js @@ -0,0 +1,8 @@ +import { checkResponse, fetchWithTimeout } from './fetchUtil'; + +export async function addAccountMFA(token) { + const mfa = await fetchWithTimeout(`/account/mfauth?agent=${token}`, { method: 'POST' }) + checkResponse(mfa); + return mfa.json(); +} + diff --git a/net/web/src/api/removeAccountMFA.js b/net/web/src/api/removeAccountMFA.js new file mode 100644 index 00000000..1b770732 --- /dev/null +++ b/net/web/src/api/removeAccountMFA.js @@ -0,0 +1,7 @@ +import { checkResponse, fetchWithTimeout } from './fetchUtil'; + +export async function removeAccountMFA(token) { + let res = await fetchWithTimeout(`/account/mfauth?agent=${token}`, { method: 'DELETE' }) + checkResponse(res); +} + diff --git a/net/web/src/api/setAccountMFA.js b/net/web/src/api/setAccountMFA.js new file mode 100644 index 00000000..0ccde145 --- /dev/null +++ b/net/web/src/api/setAccountMFA.js @@ -0,0 +1,7 @@ +import { checkResponse, fetchWithTimeout } from './fetchUtil'; + +export async function setAccountMFA(token, code) { + let res = await fetchWithTimeout(`/account/mfauth?agent=${token}&code=${code}`, { method: 'PUT' }) + checkResponse(res); +} + diff --git a/net/web/src/context/useAccountContext.hook.js b/net/web/src/context/useAccountContext.hook.js index f4777858..00f213c7 100644 --- a/net/web/src/context/useAccountContext.hook.js +++ b/net/web/src/context/useAccountContext.hook.js @@ -3,6 +3,9 @@ import { setAccountSearchable } from 'api/setAccountSearchable'; import { setAccountSeal } from 'api/setAccountSeal'; import { getAccountStatus } from 'api/getAccountStatus'; import { setAccountLogin } from 'api/setAccountLogin'; +import { addAccountMFA } from 'api/addAccountMFA'; +import { setAccountMFA } from 'api/setAccountMFA'; +import { removeAccountMFA } from 'api/removeAccountMFA'; import { StoreContext } from './StoreContext'; export function useAccountContext() { @@ -72,6 +75,17 @@ export function useAccountContext() { setSearchable: async (flag) => { await setAccountSearchable(access.current, flag); }, + enableMFA: async () => { + const secret = await addAccountMFA(access.current); + console.log("SECRET ", secret); + return secret; + }, + disableMFA: async () => { + await removeAccountMFA(access.current); + }, + confirmMFA: async (code) => { + await setAccountMFA(access.current, code); + }, setSeal: async (seal, sealKey) => { await setAccountSeal(access.current, seal); await storeContext.actions.setValue("sealKey", sealKey); diff --git a/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx b/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx index beeeb59c..fbe07751 100644 --- a/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx +++ b/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx @@ -39,6 +39,26 @@ export function AccountAccess() { } }; + const enableMFA = async (enable) => { +console.log("ENABLE: ", enable); + try { + if (enable) { + await actions.enableMFA(); + } + else { + await actions.disableMFA(); + } + } + catch (err) { + console.log(err); + modal.error({ + title: {state.strings.operationFailed}, + content: {state.strings.tryAgain}, + bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, + }); + } + } + const saveLogin = async () => { try { await actions.setLogin(); @@ -84,6 +104,12 @@ export function AccountAccess() {