mirror of https://github.com/halo-dev/halo
Support TOTP two-factor authentication for frontend
Signed-off-by: John Niang <johnniang@foxmail.com>pull/4737/head
parent
6d49047408
commit
5fab8aca5a
|
@ -71,6 +71,7 @@
|
|||
"@uppy/xhr-upload": "^3.6.0",
|
||||
"@vueuse/components": "^10.3.0",
|
||||
"@vueuse/core": "^10.3.0",
|
||||
"@vueuse/integrations": "^10.5.0",
|
||||
"@vueuse/router": "^10.3.0",
|
||||
"@vueuse/shared": "^10.3.0",
|
||||
"axios": "^0.27.2",
|
||||
|
@ -89,6 +90,7 @@
|
|||
"path-browserify": "^1.0.1",
|
||||
"pinia": "^2.1.6",
|
||||
"pretty-bytes": "^6.0.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"qs": "^6.11.1",
|
||||
"short-unique-id": "^5.0.2",
|
||||
"transliteration": "^2.3.5",
|
||||
|
|
|
@ -29,6 +29,7 @@ api/api-notification-halo-run-v1alpha1-notification-api.ts
|
|||
api/api-notification-halo-run-v1alpha1-notifier-api.ts
|
||||
api/api-notification-halo-run-v1alpha1-subscription-api.ts
|
||||
api/api-plugin-halo-run-v1alpha1-plugin-api.ts
|
||||
api/api-security-halo-run-v1alpha1-authentication-two-factor-api.ts
|
||||
api/api-security-halo-run-v1alpha1-personal-access-token-api.ts
|
||||
api/auth-halo-run-v1alpha1-auth-provider-api.ts
|
||||
api/auth-halo-run-v1alpha1-user-connection-api.ts
|
||||
|
@ -186,6 +187,7 @@ models/notifier-descriptor.ts
|
|||
models/notifier-info.ts
|
||||
models/notifier-setting-ref.ts
|
||||
models/owner-info.ts
|
||||
models/password-request.ts
|
||||
models/password-reset-email-request.ts
|
||||
models/pat-spec.ts
|
||||
models/personal-access-token-list.ts
|
||||
|
@ -283,6 +285,9 @@ models/theme-list.ts
|
|||
models/theme-spec.ts
|
||||
models/theme-status.ts
|
||||
models/theme.ts
|
||||
models/totp-auth-link-response.ts
|
||||
models/totp-request.ts
|
||||
models/two-factor-auth-settings.ts
|
||||
models/upgrade-from-uri-request.ts
|
||||
models/user-connection-list.ts
|
||||
models/user-connection-spec.ts
|
||||
|
|
|
@ -40,6 +40,7 @@ export * from "./api/api-notification-halo-run-v1alpha1-notification-api";
|
|||
export * from "./api/api-notification-halo-run-v1alpha1-notifier-api";
|
||||
export * from "./api/api-notification-halo-run-v1alpha1-subscription-api";
|
||||
export * from "./api/api-plugin-halo-run-v1alpha1-plugin-api";
|
||||
export * from "./api/api-security-halo-run-v1alpha1-authentication-two-factor-api";
|
||||
export * from "./api/api-security-halo-run-v1alpha1-personal-access-token-api";
|
||||
export * from "./api/auth-halo-run-v1alpha1-auth-provider-api";
|
||||
export * from "./api/auth-halo-run-v1alpha1-user-connection-api";
|
||||
|
|
|
@ -0,0 +1,795 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Halo Next API
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 2.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import type { Configuration } from "../configuration";
|
||||
import type { AxiosPromise, AxiosInstance, AxiosRequestConfig } from "axios";
|
||||
import globalAxios from "axios";
|
||||
// Some imports not used depending on template conditions
|
||||
// @ts-ignore
|
||||
import {
|
||||
DUMMY_BASE_URL,
|
||||
assertParamExists,
|
||||
setApiKeyToObject,
|
||||
setBasicAuthToObject,
|
||||
setBearerAuthToObject,
|
||||
setOAuthToObject,
|
||||
setSearchParams,
|
||||
serializeDataIfNeeded,
|
||||
toPathString,
|
||||
createRequestFunction,
|
||||
} from "../common";
|
||||
// @ts-ignore
|
||||
import {
|
||||
BASE_PATH,
|
||||
COLLECTION_FORMATS,
|
||||
RequestArgs,
|
||||
BaseAPI,
|
||||
RequiredError,
|
||||
} from "../base";
|
||||
// @ts-ignore
|
||||
import { PasswordRequest } from "../models";
|
||||
// @ts-ignore
|
||||
import { TotpAuthLinkResponse } from "../models";
|
||||
// @ts-ignore
|
||||
import { TotpRequest } from "../models";
|
||||
// @ts-ignore
|
||||
import { TwoFactorAuthSettings } from "../models";
|
||||
/**
|
||||
* ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi - axios parameter creator
|
||||
* @export
|
||||
*/
|
||||
export const ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiAxiosParamCreator =
|
||||
function (configuration?: Configuration) {
|
||||
return {
|
||||
/**
|
||||
* Configure a TOTP
|
||||
* @param {TotpRequest} [totpRequest]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
configurerTotp: async (
|
||||
totpRequest?: TotpRequest,
|
||||
options: AxiosRequestConfig = {}
|
||||
): Promise<RequestArgs> => {
|
||||
const localVarPath = `/apis/api.security.halo.run/v1alpha1/authentications/two-factor/totp`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = {
|
||||
method: "POST",
|
||||
...baseOptions,
|
||||
...options,
|
||||
};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication BasicAuth required
|
||||
// http basic authentication required
|
||||
setBasicAuthToObject(localVarRequestOptions, configuration);
|
||||
|
||||
// authentication BearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration);
|
||||
|
||||
localVarHeaderParameter["Content-Type"] = "application/json";
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions =
|
||||
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {
|
||||
...localVarHeaderParameter,
|
||||
...headersFromBaseOptions,
|
||||
...options.headers,
|
||||
};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(
|
||||
totpRequest,
|
||||
localVarRequestOptions,
|
||||
configuration
|
||||
);
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {PasswordRequest} [passwordRequest]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
deleteTotp: async (
|
||||
passwordRequest?: PasswordRequest,
|
||||
options: AxiosRequestConfig = {}
|
||||
): Promise<RequestArgs> => {
|
||||
const localVarPath = `/apis/api.security.halo.run/v1alpha1/authentications/two-factor/totp/-`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = {
|
||||
method: "DELETE",
|
||||
...baseOptions,
|
||||
...options,
|
||||
};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication BasicAuth required
|
||||
// http basic authentication required
|
||||
setBasicAuthToObject(localVarRequestOptions, configuration);
|
||||
|
||||
// authentication BearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration);
|
||||
|
||||
localVarHeaderParameter["Content-Type"] = "application/json";
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions =
|
||||
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {
|
||||
...localVarHeaderParameter,
|
||||
...headersFromBaseOptions,
|
||||
...options.headers,
|
||||
};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(
|
||||
passwordRequest,
|
||||
localVarRequestOptions,
|
||||
configuration
|
||||
);
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Disable Two-factor authentication
|
||||
* @param {PasswordRequest} [passwordRequest]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
disableTwoFactor: async (
|
||||
passwordRequest?: PasswordRequest,
|
||||
options: AxiosRequestConfig = {}
|
||||
): Promise<RequestArgs> => {
|
||||
const localVarPath = `/apis/api.security.halo.run/v1alpha1/authentications/two-factor/settings/disabled`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = {
|
||||
method: "PUT",
|
||||
...baseOptions,
|
||||
...options,
|
||||
};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication BasicAuth required
|
||||
// http basic authentication required
|
||||
setBasicAuthToObject(localVarRequestOptions, configuration);
|
||||
|
||||
// authentication BearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration);
|
||||
|
||||
localVarHeaderParameter["Content-Type"] = "application/json";
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions =
|
||||
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {
|
||||
...localVarHeaderParameter,
|
||||
...headersFromBaseOptions,
|
||||
...options.headers,
|
||||
};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(
|
||||
passwordRequest,
|
||||
localVarRequestOptions,
|
||||
configuration
|
||||
);
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Enable Two-factor authentication
|
||||
* @param {PasswordRequest} [passwordRequest]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
enableTwoFactor: async (
|
||||
passwordRequest?: PasswordRequest,
|
||||
options: AxiosRequestConfig = {}
|
||||
): Promise<RequestArgs> => {
|
||||
const localVarPath = `/apis/api.security.halo.run/v1alpha1/authentications/two-factor/settings/enabled`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = {
|
||||
method: "PUT",
|
||||
...baseOptions,
|
||||
...options,
|
||||
};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication BasicAuth required
|
||||
// http basic authentication required
|
||||
setBasicAuthToObject(localVarRequestOptions, configuration);
|
||||
|
||||
// authentication BearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration);
|
||||
|
||||
localVarHeaderParameter["Content-Type"] = "application/json";
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions =
|
||||
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {
|
||||
...localVarHeaderParameter,
|
||||
...headersFromBaseOptions,
|
||||
...options.headers,
|
||||
};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(
|
||||
passwordRequest,
|
||||
localVarRequestOptions,
|
||||
configuration
|
||||
);
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Get TOTP auth link, including secret
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getTotpAuthLink: async (
|
||||
options: AxiosRequestConfig = {}
|
||||
): Promise<RequestArgs> => {
|
||||
const localVarPath = `/apis/api.security.halo.run/v1alpha1/authentications/two-factor/totp/auth-link`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = {
|
||||
method: "GET",
|
||||
...baseOptions,
|
||||
...options,
|
||||
};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication BasicAuth required
|
||||
// http basic authentication required
|
||||
setBasicAuthToObject(localVarRequestOptions, configuration);
|
||||
|
||||
// authentication BearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration);
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions =
|
||||
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {
|
||||
...localVarHeaderParameter,
|
||||
...headersFromBaseOptions,
|
||||
...options.headers,
|
||||
};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Get Two-factor authentication settings.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getTwoFactorAuthenticationSettings: async (
|
||||
options: AxiosRequestConfig = {}
|
||||
): Promise<RequestArgs> => {
|
||||
const localVarPath = `/apis/api.security.halo.run/v1alpha1/authentications/two-factor/settings`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = {
|
||||
method: "GET",
|
||||
...baseOptions,
|
||||
...options,
|
||||
};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication BasicAuth required
|
||||
// http basic authentication required
|
||||
setBasicAuthToObject(localVarRequestOptions, configuration);
|
||||
|
||||
// authentication BearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration);
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions =
|
||||
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {
|
||||
...localVarHeaderParameter,
|
||||
...headersFromBaseOptions,
|
||||
...options.headers,
|
||||
};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi - functional programming interface
|
||||
* @export
|
||||
*/
|
||||
export const ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiFp = function (
|
||||
configuration?: Configuration
|
||||
) {
|
||||
const localVarAxiosParamCreator =
|
||||
ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiAxiosParamCreator(
|
||||
configuration
|
||||
);
|
||||
return {
|
||||
/**
|
||||
* Configure a TOTP
|
||||
* @param {TotpRequest} [totpRequest]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async configurerTotp(
|
||||
totpRequest?: TotpRequest,
|
||||
options?: AxiosRequestConfig
|
||||
): Promise<
|
||||
(
|
||||
axios?: AxiosInstance,
|
||||
basePath?: string
|
||||
) => AxiosPromise<TwoFactorAuthSettings>
|
||||
> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.configurerTotp(
|
||||
totpRequest,
|
||||
options
|
||||
);
|
||||
return createRequestFunction(
|
||||
localVarAxiosArgs,
|
||||
globalAxios,
|
||||
BASE_PATH,
|
||||
configuration
|
||||
);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {PasswordRequest} [passwordRequest]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async deleteTotp(
|
||||
passwordRequest?: PasswordRequest,
|
||||
options?: AxiosRequestConfig
|
||||
): Promise<
|
||||
(
|
||||
axios?: AxiosInstance,
|
||||
basePath?: string
|
||||
) => AxiosPromise<TwoFactorAuthSettings>
|
||||
> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.deleteTotp(
|
||||
passwordRequest,
|
||||
options
|
||||
);
|
||||
return createRequestFunction(
|
||||
localVarAxiosArgs,
|
||||
globalAxios,
|
||||
BASE_PATH,
|
||||
configuration
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Disable Two-factor authentication
|
||||
* @param {PasswordRequest} [passwordRequest]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async disableTwoFactor(
|
||||
passwordRequest?: PasswordRequest,
|
||||
options?: AxiosRequestConfig
|
||||
): Promise<
|
||||
(
|
||||
axios?: AxiosInstance,
|
||||
basePath?: string
|
||||
) => AxiosPromise<TwoFactorAuthSettings>
|
||||
> {
|
||||
const localVarAxiosArgs =
|
||||
await localVarAxiosParamCreator.disableTwoFactor(
|
||||
passwordRequest,
|
||||
options
|
||||
);
|
||||
return createRequestFunction(
|
||||
localVarAxiosArgs,
|
||||
globalAxios,
|
||||
BASE_PATH,
|
||||
configuration
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Enable Two-factor authentication
|
||||
* @param {PasswordRequest} [passwordRequest]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async enableTwoFactor(
|
||||
passwordRequest?: PasswordRequest,
|
||||
options?: AxiosRequestConfig
|
||||
): Promise<
|
||||
(
|
||||
axios?: AxiosInstance,
|
||||
basePath?: string
|
||||
) => AxiosPromise<TwoFactorAuthSettings>
|
||||
> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.enableTwoFactor(
|
||||
passwordRequest,
|
||||
options
|
||||
);
|
||||
return createRequestFunction(
|
||||
localVarAxiosArgs,
|
||||
globalAxios,
|
||||
BASE_PATH,
|
||||
configuration
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Get TOTP auth link, including secret
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async getTotpAuthLink(
|
||||
options?: AxiosRequestConfig
|
||||
): Promise<
|
||||
(
|
||||
axios?: AxiosInstance,
|
||||
basePath?: string
|
||||
) => AxiosPromise<TotpAuthLinkResponse>
|
||||
> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getTotpAuthLink(
|
||||
options
|
||||
);
|
||||
return createRequestFunction(
|
||||
localVarAxiosArgs,
|
||||
globalAxios,
|
||||
BASE_PATH,
|
||||
configuration
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Get Two-factor authentication settings.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async getTwoFactorAuthenticationSettings(
|
||||
options?: AxiosRequestConfig
|
||||
): Promise<
|
||||
(
|
||||
axios?: AxiosInstance,
|
||||
basePath?: string
|
||||
) => AxiosPromise<TwoFactorAuthSettings>
|
||||
> {
|
||||
const localVarAxiosArgs =
|
||||
await localVarAxiosParamCreator.getTwoFactorAuthenticationSettings(
|
||||
options
|
||||
);
|
||||
return createRequestFunction(
|
||||
localVarAxiosArgs,
|
||||
globalAxios,
|
||||
BASE_PATH,
|
||||
configuration
|
||||
);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi - factory interface
|
||||
* @export
|
||||
*/
|
||||
export const ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiFactory =
|
||||
function (
|
||||
configuration?: Configuration,
|
||||
basePath?: string,
|
||||
axios?: AxiosInstance
|
||||
) {
|
||||
const localVarFp =
|
||||
ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiFp(configuration);
|
||||
return {
|
||||
/**
|
||||
* Configure a TOTP
|
||||
* @param {ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiConfigurerTotpRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
configurerTotp(
|
||||
requestParameters: ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiConfigurerTotpRequest = {},
|
||||
options?: AxiosRequestConfig
|
||||
): AxiosPromise<TwoFactorAuthSettings> {
|
||||
return localVarFp
|
||||
.configurerTotp(requestParameters.totpRequest, options)
|
||||
.then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDeleteTotpRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
deleteTotp(
|
||||
requestParameters: ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDeleteTotpRequest = {},
|
||||
options?: AxiosRequestConfig
|
||||
): AxiosPromise<TwoFactorAuthSettings> {
|
||||
return localVarFp
|
||||
.deleteTotp(requestParameters.passwordRequest, options)
|
||||
.then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Disable Two-factor authentication
|
||||
* @param {ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDisableTwoFactorRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
disableTwoFactor(
|
||||
requestParameters: ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDisableTwoFactorRequest = {},
|
||||
options?: AxiosRequestConfig
|
||||
): AxiosPromise<TwoFactorAuthSettings> {
|
||||
return localVarFp
|
||||
.disableTwoFactor(requestParameters.passwordRequest, options)
|
||||
.then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Enable Two-factor authentication
|
||||
* @param {ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiEnableTwoFactorRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
enableTwoFactor(
|
||||
requestParameters: ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiEnableTwoFactorRequest = {},
|
||||
options?: AxiosRequestConfig
|
||||
): AxiosPromise<TwoFactorAuthSettings> {
|
||||
return localVarFp
|
||||
.enableTwoFactor(requestParameters.passwordRequest, options)
|
||||
.then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Get TOTP auth link, including secret
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getTotpAuthLink(
|
||||
options?: AxiosRequestConfig
|
||||
): AxiosPromise<TotpAuthLinkResponse> {
|
||||
return localVarFp
|
||||
.getTotpAuthLink(options)
|
||||
.then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Get Two-factor authentication settings.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getTwoFactorAuthenticationSettings(
|
||||
options?: AxiosRequestConfig
|
||||
): AxiosPromise<TwoFactorAuthSettings> {
|
||||
return localVarFp
|
||||
.getTwoFactorAuthenticationSettings(options)
|
||||
.then((request) => request(axios, basePath));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Request parameters for configurerTotp operation in ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi.
|
||||
* @export
|
||||
* @interface ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiConfigurerTotpRequest
|
||||
*/
|
||||
export interface ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiConfigurerTotpRequest {
|
||||
/**
|
||||
*
|
||||
* @type {TotpRequest}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiConfigurerTotp
|
||||
*/
|
||||
readonly totpRequest?: TotpRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for deleteTotp operation in ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi.
|
||||
* @export
|
||||
* @interface ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDeleteTotpRequest
|
||||
*/
|
||||
export interface ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDeleteTotpRequest {
|
||||
/**
|
||||
*
|
||||
* @type {PasswordRequest}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDeleteTotp
|
||||
*/
|
||||
readonly passwordRequest?: PasswordRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for disableTwoFactor operation in ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi.
|
||||
* @export
|
||||
* @interface ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDisableTwoFactorRequest
|
||||
*/
|
||||
export interface ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDisableTwoFactorRequest {
|
||||
/**
|
||||
*
|
||||
* @type {PasswordRequest}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDisableTwoFactor
|
||||
*/
|
||||
readonly passwordRequest?: PasswordRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for enableTwoFactor operation in ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi.
|
||||
* @export
|
||||
* @interface ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiEnableTwoFactorRequest
|
||||
*/
|
||||
export interface ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiEnableTwoFactorRequest {
|
||||
/**
|
||||
*
|
||||
* @type {PasswordRequest}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiEnableTwoFactor
|
||||
*/
|
||||
readonly passwordRequest?: PasswordRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi - object-oriented interface
|
||||
* @export
|
||||
* @class ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi
|
||||
* @extends {BaseAPI}
|
||||
*/
|
||||
export class ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi extends BaseAPI {
|
||||
/**
|
||||
* Configure a TOTP
|
||||
* @param {ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiConfigurerTotpRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi
|
||||
*/
|
||||
public configurerTotp(
|
||||
requestParameters: ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiConfigurerTotpRequest = {},
|
||||
options?: AxiosRequestConfig
|
||||
) {
|
||||
return ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiFp(
|
||||
this.configuration
|
||||
)
|
||||
.configurerTotp(requestParameters.totpRequest, options)
|
||||
.then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDeleteTotpRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi
|
||||
*/
|
||||
public deleteTotp(
|
||||
requestParameters: ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDeleteTotpRequest = {},
|
||||
options?: AxiosRequestConfig
|
||||
) {
|
||||
return ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiFp(
|
||||
this.configuration
|
||||
)
|
||||
.deleteTotp(requestParameters.passwordRequest, options)
|
||||
.then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Two-factor authentication
|
||||
* @param {ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDisableTwoFactorRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi
|
||||
*/
|
||||
public disableTwoFactor(
|
||||
requestParameters: ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiDisableTwoFactorRequest = {},
|
||||
options?: AxiosRequestConfig
|
||||
) {
|
||||
return ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiFp(
|
||||
this.configuration
|
||||
)
|
||||
.disableTwoFactor(requestParameters.passwordRequest, options)
|
||||
.then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Two-factor authentication
|
||||
* @param {ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiEnableTwoFactorRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi
|
||||
*/
|
||||
public enableTwoFactor(
|
||||
requestParameters: ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiEnableTwoFactorRequest = {},
|
||||
options?: AxiosRequestConfig
|
||||
) {
|
||||
return ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiFp(
|
||||
this.configuration
|
||||
)
|
||||
.enableTwoFactor(requestParameters.passwordRequest, options)
|
||||
.then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TOTP auth link, including secret
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi
|
||||
*/
|
||||
public getTotpAuthLink(options?: AxiosRequestConfig) {
|
||||
return ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiFp(
|
||||
this.configuration
|
||||
)
|
||||
.getTotpAuthLink(options)
|
||||
.then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Two-factor authentication settings.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi
|
||||
*/
|
||||
public getTwoFactorAuthenticationSettings(options?: AxiosRequestConfig) {
|
||||
return ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApiFp(
|
||||
this.configuration
|
||||
)
|
||||
.getTwoFactorAuthenticationSettings(options)
|
||||
.then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
}
|
|
@ -106,6 +106,7 @@ export * from "./notifier-descriptor-spec";
|
|||
export * from "./notifier-info";
|
||||
export * from "./notifier-setting-ref";
|
||||
export * from "./owner-info";
|
||||
export * from "./password-request";
|
||||
export * from "./password-reset-email-request";
|
||||
export * from "./pat-spec";
|
||||
export * from "./personal-access-token";
|
||||
|
@ -203,6 +204,9 @@ export * from "./theme";
|
|||
export * from "./theme-list";
|
||||
export * from "./theme-spec";
|
||||
export * from "./theme-status";
|
||||
export * from "./totp-auth-link-response";
|
||||
export * from "./totp-request";
|
||||
export * from "./two-factor-auth-settings";
|
||||
export * from "./upgrade-from-uri-request";
|
||||
export * from "./user";
|
||||
export * from "./user-connection";
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Halo Next API
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 2.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface PasswordRequest
|
||||
*/
|
||||
export interface PasswordRequest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PasswordRequest
|
||||
*/
|
||||
password: string;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Halo Next API
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 2.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface TotpAuthLinkResponse
|
||||
*/
|
||||
export interface TotpAuthLinkResponse {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof TotpAuthLinkResponse
|
||||
*/
|
||||
authLink?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof TotpAuthLinkResponse
|
||||
*/
|
||||
rawSecret?: string;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Halo Next API
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 2.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface TotpRequest
|
||||
*/
|
||||
export interface TotpRequest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof TotpRequest
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof TotpRequest
|
||||
*/
|
||||
password: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof TotpRequest
|
||||
*/
|
||||
secret: string;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Halo Next API
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 2.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface TwoFactorAuthSettings
|
||||
*/
|
||||
export interface TwoFactorAuthSettings {
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof TwoFactorAuthSettings
|
||||
*/
|
||||
available?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof TwoFactorAuthSettings
|
||||
*/
|
||||
emailVerified?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof TwoFactorAuthSettings
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof TwoFactorAuthSettings
|
||||
*/
|
||||
totpConfigured?: boolean;
|
||||
}
|
|
@ -78,6 +78,12 @@ export interface UserSpec {
|
|||
* @memberof UserSpec
|
||||
*/
|
||||
registeredAt?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UserSpec
|
||||
*/
|
||||
totpEncryptedSecret?: string;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
|
|
|
@ -110,6 +110,9 @@ importers:
|
|||
'@vueuse/core':
|
||||
specifier: ^10.3.0
|
||||
version: 10.3.0(vue@3.3.4)
|
||||
'@vueuse/integrations':
|
||||
specifier: ^10.5.0
|
||||
version: 10.7.1(axios@0.27.2)(fuse.js@6.6.2)(qrcode@1.5.3)(vue@3.3.4)
|
||||
'@vueuse/router':
|
||||
specifier: ^10.3.0
|
||||
version: 10.3.0(vue-router@4.2.4)(vue@3.3.4)
|
||||
|
@ -164,6 +167,9 @@ importers:
|
|||
pretty-bytes:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
qrcode:
|
||||
specifier: ^1.5.3
|
||||
version: 1.5.3
|
||||
qs:
|
||||
specifier: ^6.11.1
|
||||
version: 6.11.1
|
||||
|
@ -6519,6 +6525,10 @@ packages:
|
|||
resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==}
|
||||
dev: false
|
||||
|
||||
/@types/web-bluetooth@0.0.20:
|
||||
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
|
||||
dev: false
|
||||
|
||||
/@types/yargs-parser@21.0.3:
|
||||
resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
|
||||
dev: true
|
||||
|
@ -7199,10 +7209,78 @@ packages:
|
|||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/core@10.7.1(vue@3.3.4):
|
||||
resolution: {integrity: sha512-74mWHlaesJSWGp1ihg76vAnfVq9NTv1YT0SYhAQ6zwFNdBkkP+CKKJmVOEHcdSnLXCXYiL5e7MaewblfiYLP7g==}
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.20
|
||||
'@vueuse/metadata': 10.7.1
|
||||
'@vueuse/shared': 10.7.1(vue@3.3.4)
|
||||
vue-demi: 0.14.6(vue@3.3.4)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/integrations@10.7.1(axios@0.27.2)(fuse.js@6.6.2)(qrcode@1.5.3)(vue@3.3.4):
|
||||
resolution: {integrity: sha512-cKo5LEeKVHdBRBtMTOrDPdR0YNtrmN9IBfdcnY2P3m5LHVrsD0xiHUtAH1WKjHQRIErZG6rJUa6GA4tWZt89Og==}
|
||||
peerDependencies:
|
||||
async-validator: '*'
|
||||
axios: '*'
|
||||
change-case: '*'
|
||||
drauu: '*'
|
||||
focus-trap: '*'
|
||||
fuse.js: '*'
|
||||
idb-keyval: '*'
|
||||
jwt-decode: '*'
|
||||
nprogress: '*'
|
||||
qrcode: '*'
|
||||
sortablejs: '*'
|
||||
universal-cookie: '*'
|
||||
peerDependenciesMeta:
|
||||
async-validator:
|
||||
optional: true
|
||||
axios:
|
||||
optional: true
|
||||
change-case:
|
||||
optional: true
|
||||
drauu:
|
||||
optional: true
|
||||
focus-trap:
|
||||
optional: true
|
||||
fuse.js:
|
||||
optional: true
|
||||
idb-keyval:
|
||||
optional: true
|
||||
jwt-decode:
|
||||
optional: true
|
||||
nprogress:
|
||||
optional: true
|
||||
qrcode:
|
||||
optional: true
|
||||
sortablejs:
|
||||
optional: true
|
||||
universal-cookie:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@vueuse/core': 10.7.1(vue@3.3.4)
|
||||
'@vueuse/shared': 10.7.1(vue@3.3.4)
|
||||
axios: 0.27.2
|
||||
fuse.js: 6.6.2
|
||||
qrcode: 1.5.3
|
||||
vue-demi: 0.14.6(vue@3.3.4)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/metadata@10.3.0:
|
||||
resolution: {integrity: sha512-Ema3YhNOa4swDsV0V7CEY5JXvK19JI/o1szFO1iWxdFg3vhdFtCtSTP26PCvbUpnUtNHBY2wx5y3WDXND5Pvnw==}
|
||||
dev: false
|
||||
|
||||
/@vueuse/metadata@10.7.1:
|
||||
resolution: {integrity: sha512-jX8MbX5UX067DYVsbtrmKn6eG6KMcXxLRLlurGkZku5ZYT3vxgBjui2zajvUZ18QLIjrgBkFRsu7CqTAg18QFw==}
|
||||
dev: false
|
||||
|
||||
/@vueuse/router@10.3.0(vue-router@4.2.4)(vue@3.3.4):
|
||||
resolution: {integrity: sha512-WCx/BAxO0eInuOcyNRBxDLS16tnNqzdaR6/babg6AUgAIL0TCfmHBh46wJa6hhg+NMGjd6HzCaktxBasp+0c0A==}
|
||||
peerDependencies:
|
||||
|
@ -7225,6 +7303,15 @@ packages:
|
|||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/shared@10.7.1(vue@3.3.4):
|
||||
resolution: {integrity: sha512-v0jbRR31LSgRY/C5i5X279A/WQjD6/JsMzGa+eqt658oJ75IvQXAeONmwvEMrvJQKnRElq/frzBR7fhmWY5uLw==}
|
||||
dependencies:
|
||||
vue-demi: 0.14.6(vue@3.3.4)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/@webassemblyjs/ast@1.11.6:
|
||||
resolution: {integrity: sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==}
|
||||
dependencies:
|
||||
|
@ -8181,7 +8268,6 @@ packages:
|
|||
/camelcase@5.3.1:
|
||||
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/camelcase@6.3.0:
|
||||
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
|
||||
|
@ -8400,7 +8486,6 @@ packages:
|
|||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 6.2.0
|
||||
dev: true
|
||||
|
||||
/cliui@7.0.4:
|
||||
resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
|
||||
|
@ -8978,7 +9063,6 @@ packages:
|
|||
/decamelize@1.2.0:
|
||||
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/decimal.js@10.4.2:
|
||||
resolution: {integrity: sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==}
|
||||
|
@ -9192,6 +9276,10 @@ packages:
|
|||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dev: true
|
||||
|
||||
/dijkstrajs@1.0.3:
|
||||
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
|
||||
dev: false
|
||||
|
||||
/dir-glob@3.0.1:
|
||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -9367,6 +9455,10 @@ packages:
|
|||
engines: {node: '>= 4'}
|
||||
dev: true
|
||||
|
||||
/encode-utf8@1.0.3:
|
||||
resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
|
||||
dev: false
|
||||
|
||||
/encodeurl@1.0.2:
|
||||
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
@ -10608,7 +10700,6 @@ packages:
|
|||
dependencies:
|
||||
locate-path: 5.0.0
|
||||
path-exists: 4.0.0
|
||||
dev: true
|
||||
|
||||
/find-up@5.0.0:
|
||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||
|
@ -12579,7 +12670,6 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
p-locate: 4.1.0
|
||||
dev: true
|
||||
|
||||
/locate-path@6.0.0:
|
||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||
|
@ -13581,7 +13671,6 @@ packages:
|
|||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
p-try: 2.2.0
|
||||
dev: true
|
||||
|
||||
/p-limit@3.1.0:
|
||||
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
||||
|
@ -13609,7 +13698,6 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
p-limit: 2.3.0
|
||||
dev: true
|
||||
|
||||
/p-locate@5.0.0:
|
||||
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
|
||||
|
@ -13655,7 +13743,6 @@ packages:
|
|||
/p-try@2.2.0:
|
||||
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/pac-proxy-agent@7.0.1:
|
||||
resolution: {integrity: sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==}
|
||||
|
@ -13773,7 +13860,6 @@ packages:
|
|||
/path-exists@4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/path-is-absolute@1.0.1:
|
||||
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
||||
|
@ -13958,6 +14044,11 @@ packages:
|
|||
pathe: 1.1.1
|
||||
dev: true
|
||||
|
||||
/pngjs@5.0.0:
|
||||
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
dev: false
|
||||
|
||||
/polished@4.2.2:
|
||||
resolution: {integrity: sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -14583,6 +14674,17 @@ packages:
|
|||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/qrcode@1.5.3:
|
||||
resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
dijkstrajs: 1.0.3
|
||||
encode-utf8: 1.0.3
|
||||
pngjs: 5.0.0
|
||||
yargs: 15.4.1
|
||||
dev: false
|
||||
|
||||
/qs@6.11.0:
|
||||
resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
@ -14996,7 +15098,6 @@ packages:
|
|||
|
||||
/require-main-filename@2.0.0:
|
||||
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
|
||||
dev: true
|
||||
|
||||
/requireindex@1.2.0:
|
||||
resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==}
|
||||
|
@ -15427,7 +15528,6 @@ packages:
|
|||
|
||||
/set-blocking@2.0.0:
|
||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||
dev: true
|
||||
|
||||
/set-function-length@1.1.1:
|
||||
resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==}
|
||||
|
@ -17288,6 +17388,21 @@ packages:
|
|||
vue: 3.3.4
|
||||
dev: false
|
||||
|
||||
/vue-demi@0.14.6(vue@3.3.4):
|
||||
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
peerDependencies:
|
||||
'@vue/composition-api': ^1.0.0-rc.1
|
||||
vue: ^3.0.0-0 || ^2.6.0
|
||||
peerDependenciesMeta:
|
||||
'@vue/composition-api':
|
||||
optional: true
|
||||
dependencies:
|
||||
vue: 3.3.4
|
||||
dev: false
|
||||
|
||||
/vue-docgen-api@4.75.1(vue@3.3.4):
|
||||
resolution: {integrity: sha512-MECZ3uExz+ssmhD/2XrFoQQs93y17IVO1KDYTp8nr6i9GNrk67AAto6QAtilW1H/pTDPMkQxJ7w/25ZIqVtfAA==}
|
||||
peerDependencies:
|
||||
|
@ -17612,7 +17727,6 @@ packages:
|
|||
|
||||
/which-module@2.0.0:
|
||||
resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==}
|
||||
dev: true
|
||||
|
||||
/which-pm@2.0.0:
|
||||
resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==}
|
||||
|
@ -17851,7 +17965,6 @@ packages:
|
|||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
dev: true
|
||||
|
||||
/wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
|
@ -17946,7 +18059,6 @@ packages:
|
|||
|
||||
/y18n@4.0.3:
|
||||
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
||||
dev: true
|
||||
|
||||
/y18n@5.0.8:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
|
@ -17988,7 +18100,6 @@ packages:
|
|||
dependencies:
|
||||
camelcase: 5.3.1
|
||||
decamelize: 1.2.0
|
||||
dev: true
|
||||
|
||||
/yargs-parser@20.2.9:
|
||||
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
|
||||
|
@ -18014,7 +18125,6 @@ packages:
|
|||
which-module: 2.0.0
|
||||
y18n: 4.0.3
|
||||
yargs-parser: 18.1.3
|
||||
dev: true
|
||||
|
||||
/yargs@16.2.0:
|
||||
resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
|
||||
|
|
|
@ -11,6 +11,8 @@ import { submitForm } from "@formkit/core";
|
|||
import { JSEncrypt } from "jsencrypt";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ERROR_MFA_REQUIRED_TYPE } from "@/constants/error-types";
|
||||
import MfaForm from "./MfaForm.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -68,6 +70,7 @@ const handleLogin = async () => {
|
|||
withCredentials: true,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
@ -92,7 +95,16 @@ const handleLogin = async () => {
|
|||
return;
|
||||
}
|
||||
|
||||
const { title: errorTitle, detail: errorDetail } = e.response?.data || {};
|
||||
const {
|
||||
title: errorTitle,
|
||||
detail: errorDetail,
|
||||
type: errorType,
|
||||
} = e.response?.data || {};
|
||||
|
||||
if (errorType === ERROR_MFA_REQUIRED_TYPE) {
|
||||
mfaRequired.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (errorTitle || errorDetail) {
|
||||
Toast.error(errorDetail || errorTitle);
|
||||
|
@ -117,51 +129,57 @@ onMounted(() => {
|
|||
const inputClasses = {
|
||||
outer: "!py-3 first:!pt-0 last:!pb-0",
|
||||
};
|
||||
|
||||
// mfa
|
||||
const mfaRequired = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormKit
|
||||
id="login-form"
|
||||
v-model="loginForm"
|
||||
name="login-form"
|
||||
:actions="false"
|
||||
type="form"
|
||||
:classes="{
|
||||
form: '!divide-none',
|
||||
}"
|
||||
:config="{ validationVisibility: 'submit' }"
|
||||
@submit="handleLogin"
|
||||
@keyup.enter="submitForm('login-form')"
|
||||
>
|
||||
<template v-if="!mfaRequired">
|
||||
<FormKit
|
||||
:classes="inputClasses"
|
||||
name="username"
|
||||
:placeholder="$t('core.login.fields.username.placeholder')"
|
||||
:validation-label="$t('core.login.fields.username.placeholder')"
|
||||
:autofocus="true"
|
||||
type="text"
|
||||
validation="required"
|
||||
id="login-form"
|
||||
v-model="loginForm"
|
||||
name="login-form"
|
||||
:actions="false"
|
||||
type="form"
|
||||
:classes="{
|
||||
form: '!divide-none',
|
||||
}"
|
||||
:config="{ validationVisibility: 'submit' }"
|
||||
@submit="handleLogin"
|
||||
@keyup.enter="submitForm('login-form')"
|
||||
>
|
||||
<FormKit
|
||||
:classes="inputClasses"
|
||||
name="username"
|
||||
:placeholder="$t('core.login.fields.username.placeholder')"
|
||||
:validation-label="$t('core.login.fields.username.placeholder')"
|
||||
:autofocus="true"
|
||||
type="text"
|
||||
validation="required"
|
||||
>
|
||||
</FormKit>
|
||||
<FormKit
|
||||
id="passwordInput"
|
||||
:classes="inputClasses"
|
||||
name="password"
|
||||
:placeholder="$t('core.login.fields.password.placeholder')"
|
||||
:validation-label="$t('core.login.fields.password.placeholder')"
|
||||
type="password"
|
||||
validation="required"
|
||||
autocomplete="current-password"
|
||||
>
|
||||
</FormKit>
|
||||
</FormKit>
|
||||
<FormKit
|
||||
id="passwordInput"
|
||||
:classes="inputClasses"
|
||||
name="password"
|
||||
:placeholder="$t('core.login.fields.password.placeholder')"
|
||||
:validation-label="$t('core.login.fields.password.placeholder')"
|
||||
type="password"
|
||||
validation="required"
|
||||
autocomplete="current-password"
|
||||
<VButton
|
||||
class="mt-8"
|
||||
block
|
||||
:loading="loading"
|
||||
type="secondary"
|
||||
@click="submitForm('login-form')"
|
||||
>
|
||||
</FormKit>
|
||||
</FormKit>
|
||||
<VButton
|
||||
class="mt-8"
|
||||
block
|
||||
:loading="loading"
|
||||
type="secondary"
|
||||
@click="submitForm('login-form')"
|
||||
>
|
||||
{{ $t(buttonText) }}
|
||||
</VButton>
|
||||
{{ $t(buttonText) }}
|
||||
</VButton>
|
||||
</template>
|
||||
<MfaForm v-else @succeed="$emit('succeed')" />
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<script lang="ts" setup>
|
||||
import { submitForm } from "@formkit/core";
|
||||
import { Toast, VButton } from "@halo-dev/components";
|
||||
import qs from "qs";
|
||||
import axios from "axios";
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "succeed"): void;
|
||||
}>();
|
||||
|
||||
async function onSubmit({ code }: { code: string }) {
|
||||
try {
|
||||
const _csrf = document.cookie
|
||||
.split("; ")
|
||||
.find((row) => row.startsWith("XSRF-TOKEN"))
|
||||
?.split("=")[1];
|
||||
|
||||
if (!_csrf) {
|
||||
Toast.warning("CSRF token not found");
|
||||
return;
|
||||
}
|
||||
await axios.post(
|
||||
`${import.meta.env.VITE_API_URL}/login/2fa/totp`,
|
||||
qs.stringify({
|
||||
code,
|
||||
_csrf,
|
||||
}),
|
||||
{
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
emit("succeed");
|
||||
} catch (error) {
|
||||
Toast.error("验证失败");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormKit
|
||||
id="mfa-form"
|
||||
name="mfa-form"
|
||||
type="form"
|
||||
:classes="{
|
||||
form: '!divide-none',
|
||||
}"
|
||||
:config="{ validationVisibility: 'submit' }"
|
||||
@submit="onSubmit"
|
||||
@keyup.enter="submitForm('mfa-form')"
|
||||
>
|
||||
<FormKit
|
||||
:classes="{
|
||||
outer: '!py-0',
|
||||
}"
|
||||
name="code"
|
||||
placeholder="请输入两步验证码"
|
||||
validation-label="两步验证码"
|
||||
:autofocus="true"
|
||||
type="text"
|
||||
validation="required"
|
||||
>
|
||||
</FormKit>
|
||||
</FormKit>
|
||||
<VButton class="mt-8" block type="secondary" @click="submitForm('mfa-form')">
|
||||
验证
|
||||
</VButton>
|
||||
</template>
|
|
@ -0,0 +1 @@
|
|||
export const ERROR_MFA_REQUIRED_TYPE = "https://halo.run/probs/2fa-required";
|
|
@ -45,6 +45,7 @@ import {
|
|||
NotificationHaloRunV1alpha1NotifierDescriptorApi,
|
||||
ApiSecurityHaloRunV1alpha1PersonalAccessTokenApi,
|
||||
SecurityHaloRunV1alpha1PersonalAccessTokenApi,
|
||||
ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi,
|
||||
UcApiContentHaloRunV1alpha1AttachmentApi,
|
||||
UcApiContentHaloRunV1alpha1PostApi,
|
||||
UcApiContentHaloRunV1alpha1SnapshotApi,
|
||||
|
@ -247,6 +248,11 @@ function setupApiClient(axios: AxiosInstance) {
|
|||
baseURL,
|
||||
axios
|
||||
),
|
||||
twoFactor: new ApiSecurityHaloRunV1alpha1AuthenticationTwoFactorApi(
|
||||
undefined,
|
||||
baseURL,
|
||||
axios
|
||||
),
|
||||
uc: {
|
||||
post: new UcApiContentHaloRunV1alpha1PostApi(undefined, baseURL, axios),
|
||||
attachment: new UcApiContentHaloRunV1alpha1AttachmentApi(
|
||||
|
|
|
@ -22,6 +22,7 @@ import DetailTab from "./tabs/Detail.vue";
|
|||
import PersonalAccessTokensTab from "./tabs/PersonalAccessTokens.vue";
|
||||
import { useRouteQuery } from "@vueuse/router";
|
||||
import NotificationPreferences from "./tabs/NotificationPreferences.vue";
|
||||
import TwoFactor from "./tabs/TwoFactor.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -79,6 +80,12 @@ const tabs: UserTab[] = [
|
|||
component: markRaw(PersonalAccessTokensTab),
|
||||
priority: 30,
|
||||
},
|
||||
{
|
||||
id: "2fa",
|
||||
label: "两步验证",
|
||||
component: markRaw(TwoFactor),
|
||||
priority: 40,
|
||||
},
|
||||
];
|
||||
|
||||
const tabbarItems = computed(() => {
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
<script lang="ts" setup>
|
||||
import TotpConfigureModal from "./components/TotpConfigureModal.vue";
|
||||
import TotpDeletionModal from "./components/TotpDeletionModal.vue";
|
||||
import { ref } from "vue";
|
||||
import {
|
||||
VButton,
|
||||
VEntity,
|
||||
VEntityField,
|
||||
VLoading,
|
||||
VSpace,
|
||||
} from "@halo-dev/components";
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import StatusDotField from "@/components/entity-fields/StatusDotField.vue";
|
||||
import RiShieldKeyholeLine from "~icons/ri/shield-keyhole-line";
|
||||
import TwoFactorEnableModal from "./components/TwoFactorEnableModal.vue";
|
||||
import TwoFactorDisableModal from "./components/TwoFactorDisableModal.vue";
|
||||
|
||||
const { data: settings, isLoading } = useQuery({
|
||||
queryKey: ["two-factor-settings"],
|
||||
queryFn: async () => {
|
||||
const { data } =
|
||||
await apiClient.twoFactor.getTwoFactorAuthenticationSettings();
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
const twoFactorEnableModalVisible = ref(false);
|
||||
const twoFactorDisableModalVisible = ref(false);
|
||||
|
||||
function onEnabledChange(payload: Event) {
|
||||
const target = payload.target as HTMLInputElement;
|
||||
// Do not change the checked state of the checkbox
|
||||
target.checked = !target.checked;
|
||||
if (settings.value?.enabled) {
|
||||
twoFactorDisableModalVisible.value = true;
|
||||
} else {
|
||||
twoFactorEnableModalVisible.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
const totpConfigureModalVisible = ref(false);
|
||||
const totpDeletionModalVisible = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="my-5">
|
||||
<label class="flex cursor-pointer items-center space-x-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="settings?.enabled"
|
||||
@change="onEnabledChange"
|
||||
/>
|
||||
<span class="text-sm font-medium text-gray-700">启用两步验证</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<VLoading v-if="isLoading" />
|
||||
|
||||
<Transition v-else appear name="fade">
|
||||
<ul
|
||||
class="box-border h-full w-full divide-y divide-gray-100 overflow-hidden rounded-base border"
|
||||
role="list"
|
||||
>
|
||||
<li class="bg-gray-50 px-4 py-3">
|
||||
<span class="text-sm font-semibold text-gray-900">验证方式</span>
|
||||
</li>
|
||||
<li>
|
||||
<VEntity>
|
||||
<template #start>
|
||||
<VEntityField>
|
||||
<template #description>
|
||||
<RiShieldKeyholeLine />
|
||||
</template>
|
||||
</VEntityField>
|
||||
<VEntityField
|
||||
title="TOTP"
|
||||
description="使用 TOTP 应用程序配置两步验证"
|
||||
/>
|
||||
</template>
|
||||
<template #end>
|
||||
<StatusDotField
|
||||
:state="settings?.totpConfigured ? 'success' : 'default'"
|
||||
:text="settings?.totpConfigured ? '已配置' : '未配置'"
|
||||
></StatusDotField>
|
||||
<VEntityField>
|
||||
<template #description>
|
||||
<VSpace>
|
||||
<VButton size="sm" @click="totpConfigureModalVisible = true">
|
||||
{{ settings?.totpConfigured ? "重新配置" : "配置" }}
|
||||
</VButton>
|
||||
<VButton
|
||||
v-if="settings?.totpConfigured"
|
||||
size="sm"
|
||||
type="danger"
|
||||
@click="totpDeletionModalVisible = true"
|
||||
>
|
||||
停用
|
||||
</VButton>
|
||||
</VSpace>
|
||||
</template>
|
||||
</VEntityField>
|
||||
</template>
|
||||
</VEntity>
|
||||
</li>
|
||||
</ul>
|
||||
</Transition>
|
||||
|
||||
<TotpConfigureModal
|
||||
v-if="totpConfigureModalVisible"
|
||||
@close="totpConfigureModalVisible = false"
|
||||
/>
|
||||
|
||||
<TotpDeletionModal
|
||||
v-if="totpDeletionModalVisible"
|
||||
@close="totpDeletionModalVisible = false"
|
||||
/>
|
||||
|
||||
<TwoFactorEnableModal
|
||||
v-if="twoFactorEnableModalVisible"
|
||||
@close="twoFactorEnableModalVisible = false"
|
||||
/>
|
||||
|
||||
<TwoFactorDisableModal
|
||||
v-if="twoFactorDisableModalVisible"
|
||||
@close="twoFactorDisableModalVisible = false"
|
||||
/>
|
||||
</template>
|
|
@ -0,0 +1,27 @@
|
|||
<script lang="ts" setup>
|
||||
const emit = defineEmits<{
|
||||
(event: "submit", password: string): void;
|
||||
}>();
|
||||
|
||||
function onSubmit({ password }: { password: string }) {
|
||||
emit("submit", password);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormKit
|
||||
id="password-validation-form"
|
||||
type="form"
|
||||
name="password-validation-form"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<FormKit
|
||||
type="password"
|
||||
label="验证密码"
|
||||
validation="required"
|
||||
name="password"
|
||||
help="当前账号的登录密码"
|
||||
autocomplete="current-password"
|
||||
></FormKit>
|
||||
</FormKit>
|
||||
</template>
|
|
@ -0,0 +1,113 @@
|
|||
<script lang="ts" setup>
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
|
||||
import { useQRCode } from "@vueuse/integrations/useQRCode";
|
||||
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import { computed } from "vue";
|
||||
import type { TotpRequest } from "@halo-dev/api-client";
|
||||
import { ref } from "vue";
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const modal = ref();
|
||||
|
||||
const { data } = useQuery({
|
||||
queryKey: ["totp-auth-link"],
|
||||
queryFn: async () => {
|
||||
const { data } = await apiClient.twoFactor.getTotpAuthLink();
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
const qrcode = useQRCode(computed(() => data.value?.authLink || ""));
|
||||
|
||||
const { mutate, isLoading } = useMutation({
|
||||
mutationKey: ["configure-totp"],
|
||||
mutationFn: async ({ totpRequest }: { totpRequest: TotpRequest }) => {
|
||||
await apiClient.twoFactor.configurerTotp({
|
||||
totpRequest: totpRequest,
|
||||
});
|
||||
},
|
||||
onSuccess() {
|
||||
Toast.success("配置成功");
|
||||
queryClient.invalidateQueries({ queryKey: ["two-factor-settings"] });
|
||||
modal.value.close();
|
||||
},
|
||||
});
|
||||
|
||||
function onSubmit(data: TotpRequest) {
|
||||
mutate({ totpRequest: data });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VModal
|
||||
ref="modal"
|
||||
:width="500"
|
||||
:centered="false"
|
||||
title="TOTP 配置"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<div>
|
||||
<div class="mb-4 space-y-3 border-b border-gray-100 pb-4 text-gray-900">
|
||||
<div class="text-sm font-semibold">使用验证器应用扫描下方二维码:</div>
|
||||
<img :src="qrcode" class="rounded-base border border-gray-100" />
|
||||
<details>
|
||||
<summary class="cursor-pointer select-none text-sm text-gray-800">
|
||||
如果无法扫描二维码,点击查看代替步骤
|
||||
</summary>
|
||||
<div class="mt-3 rounded-base border border-gray-100 p-2">
|
||||
<span class="text-sm text-gray-600">
|
||||
使用以下代码手动配置验证器应用:
|
||||
</span>
|
||||
<div class="mt-2">
|
||||
<code
|
||||
class="select-all rounded bg-gray-200 p-1 text-xs text-gray-900"
|
||||
>
|
||||
{{ data?.rawSecret }}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<FormKit id="totp-form" type="form" name="totp-form" @submit="onSubmit">
|
||||
<FormKit
|
||||
type="number"
|
||||
name="code"
|
||||
label="验证码"
|
||||
validation="required"
|
||||
help="从验证器应用获得的 6 位验证码"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
type="password"
|
||||
label="验证密码"
|
||||
validation="required"
|
||||
name="password"
|
||||
help="当前账号的登录密码"
|
||||
autocomplete="current-password"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
:model-value="data?.rawSecret"
|
||||
type="hidden"
|
||||
name="secret"
|
||||
></FormKit>
|
||||
</FormKit>
|
||||
</div>
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
<VButton
|
||||
:loading="isLoading"
|
||||
type="secondary"
|
||||
@click="$formkit.submit('totp-form')"
|
||||
>
|
||||
完成
|
||||
</VButton>
|
||||
<VButton @click="modal.close()">关闭</VButton>
|
||||
</VSpace>
|
||||
</template>
|
||||
</VModal>
|
||||
</template>
|
|
@ -0,0 +1,59 @@
|
|||
<script lang="ts" setup>
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import { useMutation, useQueryClient } from "@tanstack/vue-query";
|
||||
import { ref } from "vue";
|
||||
import PasswordValidationForm from "./PasswordValidationForm.vue";
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const modal = ref();
|
||||
|
||||
const { mutate, isLoading } = useMutation({
|
||||
mutationKey: ["totp-deletion"],
|
||||
mutationFn: async ({ password }: { password: string }) => {
|
||||
return await apiClient.twoFactor.deleteTotp({
|
||||
passwordRequest: {
|
||||
password: password,
|
||||
},
|
||||
});
|
||||
},
|
||||
onSuccess() {
|
||||
Toast.success("停用成功");
|
||||
queryClient.invalidateQueries({ queryKey: ["two-factor-settings"] });
|
||||
modal.value.close();
|
||||
},
|
||||
});
|
||||
|
||||
function onSubmit(password: string) {
|
||||
mutate({ password });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VModal
|
||||
ref="modal"
|
||||
:width="500"
|
||||
:centered="false"
|
||||
title="停用 TOTP"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<PasswordValidationForm @submit="onSubmit" />
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
<VButton
|
||||
:loading="isLoading"
|
||||
type="danger"
|
||||
@click="$formkit.submit('password-validation-form')"
|
||||
>
|
||||
停用
|
||||
</VButton>
|
||||
<VButton @click="modal.close()">关闭</VButton>
|
||||
</VSpace>
|
||||
</template>
|
||||
</VModal>
|
||||
</template>
|
|
@ -0,0 +1,59 @@
|
|||
<script lang="ts" setup>
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import { useMutation, useQueryClient } from "@tanstack/vue-query";
|
||||
import { ref } from "vue";
|
||||
import PasswordValidationForm from "./PasswordValidationForm.vue";
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const modal = ref();
|
||||
|
||||
const { mutate, isLoading } = useMutation({
|
||||
mutationKey: ["disable-two-factor"],
|
||||
mutationFn: async ({ password }: { password: string }) => {
|
||||
return await apiClient.twoFactor.disableTwoFactor({
|
||||
passwordRequest: {
|
||||
password: password,
|
||||
},
|
||||
});
|
||||
},
|
||||
onSuccess() {
|
||||
Toast.success("停用成功");
|
||||
queryClient.invalidateQueries({ queryKey: ["two-factor-settings"] });
|
||||
modal.value.close();
|
||||
},
|
||||
});
|
||||
|
||||
function onSubmit(password: string) {
|
||||
mutate({ password });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VModal
|
||||
ref="modal"
|
||||
:width="500"
|
||||
:centered="false"
|
||||
title="停用两步验证"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<PasswordValidationForm @submit="onSubmit" />
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
<VButton
|
||||
:loading="isLoading"
|
||||
type="danger"
|
||||
@click="$formkit.submit('password-validation-form')"
|
||||
>
|
||||
停用
|
||||
</VButton>
|
||||
<VButton @click="modal.close()">关闭</VButton>
|
||||
</VSpace>
|
||||
</template>
|
||||
</VModal>
|
||||
</template>
|
|
@ -0,0 +1,59 @@
|
|||
<script lang="ts" setup>
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import { useMutation, useQueryClient } from "@tanstack/vue-query";
|
||||
import { ref } from "vue";
|
||||
import PasswordValidationForm from "./PasswordValidationForm.vue";
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const modal = ref();
|
||||
|
||||
const { mutate, isLoading } = useMutation({
|
||||
mutationKey: ["enable-two-factor"],
|
||||
mutationFn: async ({ password }: { password: string }) => {
|
||||
return await apiClient.twoFactor.enableTwoFactor({
|
||||
passwordRequest: {
|
||||
password: password,
|
||||
},
|
||||
});
|
||||
},
|
||||
onSuccess() {
|
||||
Toast.success("启用成功");
|
||||
queryClient.invalidateQueries({ queryKey: ["two-factor-settings"] });
|
||||
modal.value.close();
|
||||
},
|
||||
});
|
||||
|
||||
function onSubmit(password: string) {
|
||||
mutate({ password });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VModal
|
||||
ref="modal"
|
||||
:width="500"
|
||||
:centered="false"
|
||||
title="启用两步验证"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<PasswordValidationForm @submit="onSubmit" />
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
<VButton
|
||||
:loading="isLoading"
|
||||
type="secondary"
|
||||
@click="$formkit.submit('password-validation-form')"
|
||||
>
|
||||
启用
|
||||
</VButton>
|
||||
<VButton @click="modal.close()">关闭</VButton>
|
||||
</VSpace>
|
||||
</template>
|
||||
</VModal>
|
||||
</template>
|
Loading…
Reference in New Issue