one-api/web/berry/src/utils/common.js
OnEvent 99c8c77504
Some checks are pending
CI / Unit tests (push) Waiting to run
CI / commit_lint (push) Waiting to run
feat: add oidc support (#1725)
* feat: add the ui for configuring the third-party standard OAuth2.0/OIDC.

- update SystemSetting.js
- add setup ui
- add configuration

* feat: add the ui for "allow the OAuth 2.0 to login"

- update SystemSetting.js

* feat: add OAuth 2.0 web ui and its process functions

- update common.js
- update AuthLogin.js
- update config.js

* fix: missing "Userinfo" endpoint configuration entry, used by OAuth clients to request user information from the IdP.

- update config.js
- update SystemSetting.js

* feat: updated the icons for Lark and OIDC to match the style of the icons for WeChat, EMail, GitHub.

- update lark.svg
- new oidc.svg

* refactor: Changing OAuth 2.0 to OIDC

* feat: add OIDC login method

* feat: Add support for OIDC login to the backend

* fix: Change the AppId and AppSecret on the Web UI to the standard usage: ClientId, ClientSecret.

* feat: Support quick configuration of OIDC through Well-Known Discovery Endpoint

* feat: Standardize terminology, add well-known configuration

- Change the AppId and AppSecret on the Server End to the standard usage: ClientId, ClientSecret.
- add Well-Known configuration to store in database, no actual use in server end but store and display in web ui only
2024-09-21 23:03:20 +08:00

248 lines
6.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { enqueueSnackbar } from 'notistack';
import { snackbarConstants } from 'constants/SnackbarConstants';
import { API } from './api';
export function getSystemName() {
let system_name = localStorage.getItem('system_name');
if (!system_name) return 'One API';
return system_name;
}
export function isMobile() {
return window.innerWidth <= 600;
}
// eslint-disable-next-line
export function SnackbarHTMLContent({ htmlContent }) {
return <div dangerouslySetInnerHTML={{ __html: htmlContent }} />;
}
export function getSnackbarOptions(variant) {
let options = snackbarConstants.Common[variant];
if (isMobile()) {
// 合并 options 和 snackbarConstants.Mobile
options = { ...options, ...snackbarConstants.Mobile };
}
return options;
}
export function showError(error) {
if (error.message) {
if (error.name === 'AxiosError') {
switch (error.response.status) {
case 429:
enqueueSnackbar('错误:请求次数过多,请稍后再试!', getSnackbarOptions('ERROR'));
break;
case 500:
enqueueSnackbar('错误:服务器内部错误,请联系管理员!', getSnackbarOptions('ERROR'));
break;
case 405:
enqueueSnackbar('本站仅作演示之用,无服务端!', getSnackbarOptions('INFO'));
break;
default:
enqueueSnackbar('错误:' + error.message, getSnackbarOptions('ERROR'));
}
return;
}
} else {
enqueueSnackbar('错误:' + error, getSnackbarOptions('ERROR'));
}
}
export function showNotice(message, isHTML = false) {
if (isHTML) {
enqueueSnackbar(<SnackbarHTMLContent htmlContent={message} />, getSnackbarOptions('NOTICE'));
} else {
enqueueSnackbar(message, getSnackbarOptions('NOTICE'));
}
}
export function showWarning(message) {
enqueueSnackbar(message, getSnackbarOptions('WARNING'));
}
export function showSuccess(message) {
enqueueSnackbar(message, getSnackbarOptions('SUCCESS'));
}
export function showInfo(message) {
enqueueSnackbar(message, getSnackbarOptions('INFO'));
}
export async function getOAuthState() {
const res = await API.get('/api/oauth/state');
const { success, message, data } = res.data;
if (success) {
return data;
} else {
showError(message);
return '';
}
}
export async function onGitHubOAuthClicked(github_client_id, openInNewTab = false) {
const state = await getOAuthState();
if (!state) return;
let url = `https://github.com/login/oauth/authorize?client_id=${github_client_id}&state=${state}&scope=user:email`;
if (openInNewTab) {
window.open(url);
} else {
window.location.href = url;
}
}
export async function onLarkOAuthClicked(lark_client_id) {
const state = await getOAuthState();
if (!state) return;
let redirect_uri = `${window.location.origin}/oauth/lark`;
window.open(`https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri=${redirect_uri}&app_id=${lark_client_id}&state=${state}`);
}
export async function onOidcClicked(auth_url, client_id, openInNewTab = false) {
const state = await getOAuthState();
if (!state) return;
const redirect_uri = `${window.location.origin}/oauth/oidc`;
const response_type = "code";
const scope = "openid profile email";
const url = `${auth_url}?client_id=${client_id}&redirect_uri=${redirect_uri}&response_type=${response_type}&scope=${scope}&state=${state}`;
if (openInNewTab) {
window.open(url);
} else
{
window.location.href = url;
}
}
export function isAdmin() {
let user = localStorage.getItem('user');
if (!user) return false;
user = JSON.parse(user);
return user.role >= 10;
}
export function timestamp2string(timestamp) {
let date = new Date(timestamp * 1000);
let year = date.getFullYear().toString();
let month = (date.getMonth() + 1).toString();
let day = date.getDate().toString();
let hour = date.getHours().toString();
let minute = date.getMinutes().toString();
let second = date.getSeconds().toString();
if (month.length === 1) {
month = '0' + month;
}
if (day.length === 1) {
day = '0' + day;
}
if (hour.length === 1) {
hour = '0' + hour;
}
if (minute.length === 1) {
minute = '0' + minute;
}
if (second.length === 1) {
second = '0' + second;
}
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
}
export function calculateQuota(quota, digits = 2) {
let quotaPerUnit = localStorage.getItem('quota_per_unit');
quotaPerUnit = parseFloat(quotaPerUnit);
return (quota / quotaPerUnit).toFixed(digits);
}
export function renderQuota(quota, digits = 2) {
let displayInCurrency = localStorage.getItem('display_in_currency');
displayInCurrency = displayInCurrency === 'true';
if (displayInCurrency) {
return '$' + calculateQuota(quota, digits);
}
return renderNumber(quota);
}
export const verifyJSON = (str) => {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
};
export function renderNumber(num) {
if (num >= 1000000000) {
return (num / 1000000000).toFixed(1) + 'B';
} else if (num >= 1000000) {
return (num / 1000000).toFixed(1) + 'M';
} else if (num >= 10000) {
return (num / 1000).toFixed(1) + 'k';
} else {
return num;
}
}
export function renderQuotaWithPrompt(quota, digits) {
let displayInCurrency = localStorage.getItem('display_in_currency');
displayInCurrency = displayInCurrency === 'true';
if (displayInCurrency) {
return `(等价金额:${renderQuota(quota, digits)}`;
}
return '';
}
export function downloadTextAsFile(text, filename) {
let blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
let url = URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
}
export function removeTrailingSlash(url) {
if (url.endsWith('/')) {
return url.slice(0, -1);
} else {
return url;
}
}
let channelModels = undefined;
export async function loadChannelModels() {
const res = await API.get('/api/models');
const { success, data } = res.data;
if (!success) {
return;
}
channelModels = data;
localStorage.setItem('channel_models', JSON.stringify(data));
}
export function getChannelModels(type) {
if (channelModels !== undefined && type in channelModels) {
return channelModels[type];
}
let models = localStorage.getItem('channel_models');
if (!models) {
return [];
}
channelModels = JSON.parse(models);
if (type in channelModels) {
return channelModels[type];
}
return [];
}
export function copy(text, name = '') {
try {
navigator.clipboard.writeText(text);
} catch (error) {
text = `复制${name}失败,请手动复制:<br /><br />${text}`;
enqueueSnackbar(<SnackbarHTMLContent htmlContent={text} />, getSnackbarOptions('COPY'));
return;
}
showSuccess(`复制${name}成功!`);
}