mirror of
https://github.com/labring/sealos.git
synced 2026-09-24 15:46:19 +08:00
feat. change desktop to use config file. (#4709)
* change desktop to use config file. * chore: fix logo svg config and related codes. * chore: fix logo svg config and related codes. * chore: bugs. * chore: update enable service to use global config. * chore: update build related files. * chore: update build related files. * chore: update sealos cloud cluster image to adapt desktop using yaml as config. Signed-off-by: yy <lingdie.yy@outlook.com> Signed-off-by: yy <lingdie.yy@outlook.com> * chore: update build related files. * merge(desktop):merge config (#33) chore(desktop):fix type error * chore: fix build error. --------- Signed-off-by: yy <lingdie.yy@outlook.com> Co-authored-by: xudaotutou <13435638964@163.com>
This commit is contained in:
@@ -3,16 +3,54 @@ kind: Config
|
||||
metadata:
|
||||
name: secret
|
||||
spec:
|
||||
path: manifests/secret.yaml
|
||||
# do not modify this image, it's used by ci.
|
||||
match: ghcr.io/labring/sealos-cloud-desktop-frontend:latest
|
||||
strategy: merge
|
||||
path: manifests/configmap.yaml
|
||||
strategy: override
|
||||
data: |
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: desktop-frontend-config
|
||||
namespace: sealos
|
||||
data:
|
||||
mongodb_uri: <your-mongodb-uri-base64>
|
||||
jwt_secret: <your-jwt-secret-base64>
|
||||
password_salt: <your-password-salt-base64>
|
||||
jwt_secret_region: <your-jwt-secret-region-base64>
|
||||
region_database_url: <your-region-database-url-base64>
|
||||
global_database_url: <your-global-database-url-base64>
|
||||
region_uid: <your-local-region-uid-base64>
|
||||
config.yaml : |
|
||||
cloud:
|
||||
domain: "{{ .cloudDomain }}"
|
||||
port: "{{ .cloudPort }}"
|
||||
regionUID: "<your-local-region-uid>"
|
||||
certSecretName: "{{ .certSecretName }}"
|
||||
common:
|
||||
guideEnabled: "false"
|
||||
apiEnabled: "false"
|
||||
rechargeEnabled: "false"
|
||||
cfSiteKey: ""
|
||||
database:
|
||||
mongodbURI: "<your-mongodb-uri>"
|
||||
globalCockroachdbURI: "<your-global-database-url>"
|
||||
regionalCockroachdbURI: "<your-regional-database-url>"
|
||||
desktop:
|
||||
layout:
|
||||
title: "Sealos Cloud"
|
||||
logo: "/logo.png"
|
||||
backgroundImage: "/images/bg-blue.svg"
|
||||
meta:
|
||||
title: "Sealos Cloud"
|
||||
description: "Sealos Cloud"
|
||||
keywords: "Sealos Cloud"
|
||||
scripts: []
|
||||
common:
|
||||
githubStarEnabled: "true"
|
||||
auth:
|
||||
proxyAddress: ""
|
||||
callbackURL: "https://{{ .cloudDomain }}{{ if .cloudPort }}:{{ .cloudPort }}{{ end }}/callback"
|
||||
signUpEnabled: "true"
|
||||
baiduToken: ""
|
||||
invite:
|
||||
enabled: "false"
|
||||
jwt:
|
||||
internal: "<your-internal-jwt-secret>"
|
||||
regional: "<your-regional-jwt-secret>"
|
||||
global: "<your-global-jwt-secret>"
|
||||
idp:
|
||||
password:
|
||||
enabled: "true"
|
||||
salt: "<your-password-salt>"
|
||||
@@ -135,32 +135,33 @@ function gen_cockroachdbUri() {
|
||||
}
|
||||
|
||||
function gen_saltKey() {
|
||||
password_salt=$(kubectl get secret desktop-frontend-secret -n sealos -o jsonpath="{.data.password_salt}" 2>/dev/null || true)
|
||||
password_salt=$(kubectl get configmap desktop-frontend-config -n sealos -o jsonpath='{.data.config\.yaml}' | grep "salt:" | awk '{print $2}' 2>/dev/null || true)
|
||||
if [[ -z "$password_salt" ]]; then
|
||||
saltKey=$(tr -dc 'a-z0-9' </dev/urandom | head -c64 | base64 -w 0)
|
||||
saltKey=$(tr -dc 'a-z0-9' </dev/urandom | head -c64)
|
||||
else
|
||||
saltKey=$password_salt
|
||||
fi
|
||||
}
|
||||
|
||||
function gen_regionUID(){
|
||||
uid=$(kubectl get secret desktop-frontend-secret -n sealos -o jsonpath="{.data.region_uid}" 2>/dev/null || true)
|
||||
uid=$(kubectl get configmap desktop-frontend-config -n sealos -o jsonpath='{.data.config\.yaml}' | grep "regionUID:" | awk '{print $2}' 2>/dev/null || true)
|
||||
if [[ -z "$uid" ]]; then
|
||||
localRegionUID=$(uuidgen)
|
||||
else
|
||||
localRegionUID=$(echo -n "$uid" | base64 -d)
|
||||
localRegionUID=$(echo -n "$uid")``
|
||||
fi
|
||||
}
|
||||
|
||||
function mutate_desktop_config() {
|
||||
# mutate etc/sealos/desktop-config.yaml by using mongodb uri and two random base64 string
|
||||
sed -i -e "s;<your-mongodb-uri-base64>;$(echo -n "${mongodbUri}/sealos-auth?authSource=admin" | base64 -w 0);" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-jwt-secret-base64>;$(tr -cd 'a-z0-9' </dev/urandom | head -c64 | base64 -w 0);" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-jwt-secret-region-base64>;$(tr -cd 'a-z0-9' </dev/urandom | head -c64 | base64 -w 0);" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-password-salt-base64>;$saltKey;" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-region-database-url-base64>;$(echo -n "${cockroachdbLocalUri}" | base64 -w 0);" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-global-database-url-base64>;$(echo -n "${cockroachdbGlobalUri}" | base64 -w 0);" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-local-region-uid-base64>;$(echo -n "${localRegionUID}" | base64 -w 0);" etc/sealos/desktop-config.yaml
|
||||
# mutate etc/sealos/desktop-config.yaml by using mongodb uri and two random string
|
||||
sed -i -e "s;<your-mongodb-uri>;$(echo -n "${mongodbUri}/sealos-auth?authSource=admin");" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-internal-jwt-secret>;$(tr -cd 'a-z0-9' </dev/urandom | head -c64);" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-regional-jwt-secret>;$(tr -cd 'a-z0-9' </dev/urandom | head -c64);" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-global-jwt-secret>;$(tr -cd 'a-z0-9' </dev/urandom | head -c64);" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-password-salt>;$saltKey;" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-regional-database-url>;$(echo -n "${cockroachdbLocalUri}");" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-global-database-url>;$(echo -n "${cockroachdbGlobalUri}");" etc/sealos/desktop-config.yaml
|
||||
sed -i -e "s;<your-local-region-uid>;$(echo -n "${localRegionUID}");" etc/sealos/desktop-config.yaml
|
||||
}
|
||||
|
||||
function create_tls_secret {
|
||||
@@ -223,7 +224,7 @@ function sealos_run_controller {
|
||||
|
||||
|
||||
function sealos_authorize {
|
||||
sealos run tars/job-init.tar --env PASSWORD_SALT="$(echo -n "$saltKey" | base64 -d)"
|
||||
sealos run tars/job-init.tar --env PASSWORD_SALT="$(echo -n "$saltKey")"
|
||||
sealos run tars/job-heartbeat.tar
|
||||
|
||||
# wait for admin user create
|
||||
|
||||
@@ -27,7 +27,7 @@ yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
data/config.local.json
|
||||
data/*.local
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
cloud:
|
||||
domain: "127.0.0.1.nip.io"
|
||||
port: ""
|
||||
regionUID: "thisiaregionuid"
|
||||
certSecretName: "wildcard-cert"
|
||||
common:
|
||||
guideEnabled: "false"
|
||||
apiEnabled: "false"
|
||||
rechargeEnabled: "false"
|
||||
cfSiteKey: ""
|
||||
database:
|
||||
mongodbURI: "thisismongodburi"
|
||||
globalCockroachdbURI: "thisisglobalcockroachdburi"
|
||||
regionalCockroachdbURI: "thisisregionalcockroachdburi"
|
||||
desktop:
|
||||
layout:
|
||||
title: "Sealos Cloud"
|
||||
logo: "/logo.png"
|
||||
backgroundImage: "/images/bg-blue.svg"
|
||||
meta:
|
||||
title: "Sealos Cloud"
|
||||
description: "Sealos Cloud"
|
||||
keywords: "Sealos Cloud"
|
||||
scripts: []
|
||||
common:
|
||||
githubStarEnabled: "false"
|
||||
auth:
|
||||
proxyAddress: ""
|
||||
callbackURL: "https://127.0.0.1.nip.io/callback"
|
||||
signUpEnabled: "true"
|
||||
baiduToken: ""
|
||||
invite:
|
||||
enabled: "false"
|
||||
jwt:
|
||||
internal: "thisisinternaljwt"
|
||||
regional: "thisisregionaljwt"
|
||||
global: "thisisglobaljwt"
|
||||
idp:
|
||||
password:
|
||||
enabled: "true"
|
||||
salt: "thisispasswordsalt"
|
||||
# github:
|
||||
# enabled: "{{ .githubEnabled }}"
|
||||
# clientId: "{{ .githubClientID }}"
|
||||
# clientSecret: "{{ .githubClientSecret }}"
|
||||
# wechat:
|
||||
# enabled: "{{ .wechatEnabled }}"
|
||||
# clientId: "{{ .wechatClientID }}"
|
||||
# clientSecret: "{{ .wechatClientSecret }}"
|
||||
# sms:
|
||||
# ali:
|
||||
# enabled: "{{ .smsEnabled }}"
|
||||
# endpoint: "{{ .aliSmsEndpoint }}"
|
||||
# signName: "{{ .aliSmsSignName }}"
|
||||
# accessKeyId: "{{ .aliAccessKeyID }}"
|
||||
# accessKeySecret: "{{ .aliAccessKeySecret }}"
|
||||
# oauth2:
|
||||
# enabled: "{{ .oauth2Enabled }}"
|
||||
# callbackURL: "https://{{ .cloudDomain }}{{ if .cloudPort }}:{{ .cloudPort }}{{ end }}/callback"
|
||||
# clientId: "{{ .oauth2ClientId }}"
|
||||
# clientSecret: "{{ .oauth2ClientSecret }}"
|
||||
# authURL: "{{ .oauth2AuthURL }}"
|
||||
# tokenURL: "{{ .oauth2TokenURL }}"
|
||||
# userInfoURL: "{{ .oauth2UserInfoURL }}"
|
||||
@@ -8,11 +8,5 @@ COPY scripts scripts
|
||||
ENV cloudDomain="127.0.0.1.nip.io"
|
||||
ENV cloudPort=""
|
||||
ENV certSecretName="wildcard-cert"
|
||||
ENV passWordEnabled="false"
|
||||
ENV githubEnabled="false"
|
||||
ENV wechatEnabled="false"
|
||||
ENV smsEnabled="false"
|
||||
ENV signUpEnabled="true"
|
||||
ENV apiEnabled="false"
|
||||
|
||||
CMD ["bash scripts/init.sh"]
|
||||
|
||||
@@ -6,48 +6,81 @@ sealos build -t docker.io/labring/sealos-cloud-desktop:latest -f Kubefile .
|
||||
|
||||
### Env
|
||||
|
||||
| Name | Description | Default |
|
||||
|----------------------------|-----------------------------|----------------------------------------|
|
||||
| `cloudDomain` | sealos cloud domain | `cloud.example.com` |
|
||||
| `wildcardCertSecretName` | wildcard cert secret name | `wildcard-cert` |
|
||||
| Name | Description | Default |
|
||||
|----------------------------|-----------------------------|--------------------|
|
||||
| `cloudDomain` | sealos cloud domain | `127.0.0.1.nip.io` |
|
||||
| `wildcardCertSecretName` | wildcard cert secret name | `wildcard-cert` |
|
||||
|
||||
### Config
|
||||
|
||||
If you enable password login (which is enabled by default), you need to set the password salt by using a config file.
|
||||
|
||||
And this is a command to generate a password salt:
|
||||
```shell
|
||||
echo -n "your-password-salt" | base64
|
||||
```
|
||||
|
||||
|
||||
Here is a config file example:
|
||||
```yaml
|
||||
# desktop-config.yaml
|
||||
apiVersion: apps.sealos.io/v1beta1
|
||||
kind: Config
|
||||
metadata:
|
||||
name: secret
|
||||
name: configMap
|
||||
spec:
|
||||
path: manifests/secret.yaml
|
||||
match: docker.io/labring/sealos-cloud-desktop:latest
|
||||
strategy: merge
|
||||
path: manifests/configmap.yaml
|
||||
strategy: override
|
||||
data: |
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: desktop-frontend-config
|
||||
namespace: sealos
|
||||
data:
|
||||
mongodb_uri: <your-mongodb-uri-base64>
|
||||
jwt_secret: <your-jwt-secret-base64>
|
||||
password_salt: <your-password-salt-base64>
|
||||
config.yaml : |
|
||||
cloud:
|
||||
domain: "127.0.0.1.nip.io"
|
||||
port: ""
|
||||
regionUID: "thisiaregionuid"
|
||||
certSecretName: "wildcard-cert"
|
||||
common:
|
||||
guideEnabled: "false"
|
||||
apiEnabled: "false"
|
||||
rechargeEnabled: "false"
|
||||
cfSiteKey: ""
|
||||
database:
|
||||
mongodbUri: "thisismongodburi"
|
||||
globalCockroachdbURI: "thisisglobalcockroachdburi"
|
||||
regionalCockroachdbURI: "thisisregionalcockroachdburi"
|
||||
desktop:
|
||||
layout:
|
||||
title: "Sealos Cloud"
|
||||
logo: "/logo.png"
|
||||
backgroundImage: "/images/bg-blue.svg"
|
||||
meta:
|
||||
title: "Sealos Cloud"
|
||||
description: "Sealos Cloud"
|
||||
keywords: "Sealos Cloud"
|
||||
scripts: []
|
||||
common:
|
||||
githubStarEnabled: "false"
|
||||
auth:
|
||||
proxyAddress: ""
|
||||
callbackURL: "https://127.0.0.1.nip.io/callback"
|
||||
signUpEnabled: "true"
|
||||
baiduToken: ""
|
||||
invite:
|
||||
enabled: "false"
|
||||
jwt:
|
||||
internal: "thisisinternaljwt"
|
||||
regional: "thisisregionaljwt"
|
||||
global: "thisisglobaljwt"
|
||||
idp:
|
||||
password:
|
||||
enabled: "true"
|
||||
salt: "thisispasswordsalt"
|
||||
|
||||
```
|
||||
|
||||
*Please make sure `spec.match` is the same as the image you want to run*
|
||||
|
||||
### How to run
|
||||
|
||||
```shell
|
||||
sealos run \
|
||||
--env cloudDomain="127.0.0.1.nip.io" \
|
||||
--env wildcardCertSecretName="wildcard-cert" \
|
||||
--env passwordEnabled="true" \
|
||||
docker.io/labring/sealos-cloud-desktop:latest \
|
||||
--config-file desktop-config.yaml
|
||||
```
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: desktop-frontend-config
|
||||
namespace: sealos
|
||||
data:
|
||||
config.yaml : |
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: desktop-frontend-config
|
||||
namespace: sealos
|
||||
data:
|
||||
config.yaml : |
|
||||
cloud:
|
||||
domain: "{{ .cloudDomain }}"
|
||||
port: "{{ .cloudPort }}"
|
||||
regionUID: "<your-local-region-uid-base64>"
|
||||
certSecretName: "{{ .certSecretName }}"
|
||||
common:
|
||||
guideEnabled: "false"
|
||||
apiEnabled: "false"
|
||||
rechargeEnabled: "false"
|
||||
cfSiteKey: ""
|
||||
database:
|
||||
mongodbURI: "<your-mongodb-uri-base64>"
|
||||
globalCockroachdbURI: "<your-global-database-url-base64>"
|
||||
regionalCockroachdbURI: "<your-region-database-url-base64>"
|
||||
desktop:
|
||||
layout:
|
||||
title: "Sealos Cloud"
|
||||
logo: "/logo.png"
|
||||
backgroundImage: "/images/bg-blue.svg"
|
||||
meta:
|
||||
title: "Sealos Cloud"
|
||||
description: "Sealos Cloud"
|
||||
keywords: "Sealos Cloud"
|
||||
scripts: []
|
||||
common:
|
||||
githubStarEnabled: "true"
|
||||
auth:
|
||||
proxyAddress: ""
|
||||
callbackURL: "https://{{ .cloudDomain }}{{ if .cloudPort }}:{{ .cloudPort }}{{ end }}/callback"
|
||||
signUpEnabled: "true"
|
||||
baiduToken: ""
|
||||
invite:
|
||||
enabled: "false"
|
||||
jwt:
|
||||
internal: "<your-jwt-secret-base64>"
|
||||
regional: "<your-jwt-secret-base64>"
|
||||
global: "<your-jwt-secret-base64>"
|
||||
idp:
|
||||
password:
|
||||
enabled: "true"
|
||||
salt: "<your-password-salt-base64>"
|
||||
@@ -29,26 +29,6 @@ spec:
|
||||
selector:
|
||||
app: desktop-frontend
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: desktop-frontend-config
|
||||
namespace: sealos
|
||||
data:
|
||||
config.yaml: |-
|
||||
addr: :3000
|
||||
config.json: |-
|
||||
{
|
||||
"scripts": [],
|
||||
"isSystemConfigEnabled": true,
|
||||
"backgroundImageUrl": '/images/bg-blue.svg',
|
||||
"imageFallBackUrl": 'logo.svg',
|
||||
"title": 'Sealos',
|
||||
"metaTitle": 'Sealos Cloud',
|
||||
"metaDescription": 'sealos cloud dashboard',
|
||||
"showGithubStar": true
|
||||
}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -75,155 +55,16 @@ spec:
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
export REGIONAL_COCKROACHDB_URI=$(cat /app/data/config.yaml | awk '/regionalCockroachdbUri:/ {print $2}' | tr -d '"')
|
||||
export GLOBAL_COCKROACHDB_URI=$(cat /app/data/config.yaml | awk '/globalCockroachdbUri:/ {print $2}' | tr -d '"')
|
||||
prisma migrate deploy --schema /app/desktop/prisma/global/schema.prisma
|
||||
prisma migrate deploy --schema /app/desktop/prisma/region/schema.prisma
|
||||
env:
|
||||
- name: GLOBAL_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: global_database_url
|
||||
name: desktop-frontend-secret
|
||||
- name: REGION_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: region_database_url
|
||||
name: desktop-frontend-secret
|
||||
volumeMounts:
|
||||
- mountPath: /app/data/config.yaml
|
||||
name: desktop-frontend-volume
|
||||
subPath: config.yaml
|
||||
containers:
|
||||
- name: desktop-frontend
|
||||
env:
|
||||
# callback url is used for oauth2 login, required
|
||||
- name: CALLBACK_URL
|
||||
value: https://{{ .cloudDomain }}{{ if .cloudPort }}:{{ .cloudPort }}{{ end }}/callback
|
||||
# mongodb uri, required
|
||||
- name: MONGODB_URI
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: mongodb_uri
|
||||
# jwt secret, required
|
||||
- name: JWT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: jwt_secret
|
||||
|
||||
# set to true to enable password login, modify the PASSWORD_SALT env to change the salt
|
||||
- name: PASSWORD_ENABLED
|
||||
value: '{{ .passwordEnabled }}'
|
||||
# set to true to enable github login
|
||||
- name: GITHUB_ENABLED
|
||||
value: '{{ .githubEnabled }}'
|
||||
# set to true to enable wechat login
|
||||
- name: WECHAT_ENABLED
|
||||
value: '{{ .wechatEnabled }}'
|
||||
# set to true to enable sms login
|
||||
- name: SMS_ENABLED
|
||||
value: '{{ .smsEnabled }}'
|
||||
# set to true to enable sign up
|
||||
- name: SIGN_UP_ENABLED
|
||||
value: '{{ .signUpEnabled }}'
|
||||
# set to true to open api
|
||||
- name: API_ENABLED
|
||||
value: '{{ .apiEnabled }}'
|
||||
# password login env
|
||||
- name: PASSWORD_SALT
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: password_salt
|
||||
# github login env
|
||||
- name: GITHUB_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: github_client_id
|
||||
optional: true
|
||||
- name: GITHUB_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: github_client_secret
|
||||
optional: true
|
||||
# wechat login env
|
||||
- name: WECHAT_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: wechat_client_id
|
||||
optional: true
|
||||
- name: WECHAT_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: wechat_client_secret
|
||||
optional: true
|
||||
# sms login env
|
||||
- name: ALI_ENDPOINT
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: ali_sms_endpoint
|
||||
optional: true
|
||||
- name: ALI_ACCESS_KEY_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: ali_access_key_id
|
||||
optional: true
|
||||
- name: ALI_ACCESS_KEY_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: ali_access_key_secret
|
||||
optional: true
|
||||
- name: ALI_SIGN_NAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: ali_sms_sign_name
|
||||
optional: true
|
||||
- name: ALI_TEMPLATE_CODE
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: desktop-frontend-secret
|
||||
key: ali_sms_template_code
|
||||
optional: true
|
||||
- name: SEALOS_CLOUD_DOMAIN
|
||||
value: {{ .cloudDomain }}
|
||||
- name: INVITE_ENABLED
|
||||
value: "false"
|
||||
- name: GUIDE_ENABLED
|
||||
value: "false"
|
||||
- name: GLOBAL_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: global_database_url
|
||||
name: desktop-frontend-secret
|
||||
- name: REGION_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: region_database_url
|
||||
name: desktop-frontend-secret
|
||||
- name: BILLING_URI
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: billing_uri
|
||||
name: desktop-frontend-secret
|
||||
- name: JWT_SECRET_REGION
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: jwt_secret_region
|
||||
name: desktop-frontend-secret
|
||||
- name: JWT_SECRET_APP
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: jwt_secret_app
|
||||
name: desktop-frontend-secret
|
||||
- name: REGION_UID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: region_uid
|
||||
name: desktop-frontend-secret
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
@@ -234,12 +75,9 @@ spec:
|
||||
image: ghcr.io/labring/sealos-desktop-frontend:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
volumeMounts:
|
||||
- name: desktop-frontend-volume
|
||||
mountPath: /config.yaml
|
||||
subPath: config.yaml
|
||||
- mountPath: /app/data/config.json
|
||||
- mountPath: /app/data/config.yaml
|
||||
name: desktop-frontend-volume
|
||||
subPath: config.json
|
||||
subPath: config.yaml
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
@@ -250,16 +88,16 @@ spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: "app"
|
||||
operator: In
|
||||
values:
|
||||
- desktop-frontend
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: "app"
|
||||
operator: In
|
||||
values:
|
||||
- desktop-frontend
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
volumes:
|
||||
- name: desktop-frontend-volume
|
||||
configMap:
|
||||
name: desktop-frontend-config
|
||||
name: desktop-frontend-config
|
||||
@@ -1,51 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: desktop-frontend-secret
|
||||
namespace: sealos
|
||||
type: Opaque
|
||||
data:
|
||||
# base64 encode account service url, required
|
||||
# default value is "http://account-service.account-system.svc:2333"
|
||||
billing_uri: "aHR0cDovL2FjY291bnQtc2VydmljZS5hY2NvdW50LXN5c3RlbS5zdmM6MjMzMw=="
|
||||
|
||||
|
||||
# base64 encoded mongodb uri, required
|
||||
mongodb_uri: ""
|
||||
# base64 encoded cockroachdb uri for global, required
|
||||
global_database_url: ""
|
||||
# base64 encoded cockroachdb uri for current region, required
|
||||
region_database_url: ""
|
||||
# base64 encoded jwt secret, required
|
||||
jwt_secret: ""
|
||||
# base64 encoded global jwt secret, required
|
||||
jwt_secret_region: ""
|
||||
# base64 encoded provider jwt secret, required
|
||||
jwt_secret_app: ""
|
||||
|
||||
# base64 encoded password salt, required if env PASSWORD_ENABLED is true
|
||||
# please use a random string and do not change it after deployment
|
||||
password_salt: ""
|
||||
|
||||
# base64 encoded GitHub client id, required if env GITHUB_ENABLED is true
|
||||
github_client_id: ""
|
||||
# base64 encoded GitHub client secret, required if env GITHUB_ENABLED is true
|
||||
github_client_secret: ""
|
||||
|
||||
# base64 encoded WeChat client id, required if env WECHAT_ENABLED is true
|
||||
wechat_client_id: ""
|
||||
# base64 encoded WeChat client secret, required if env WECHAT_ENABLED is true
|
||||
wechat_client_secret: ""
|
||||
|
||||
# base64 encoded ali sms endpoint, required if env SMS_ENABLED is true
|
||||
ali_sms_endpoint: ""
|
||||
# base64 encoded ali access key id, required if env SMS_ENABLED is true
|
||||
ali_access_key_id: ""
|
||||
# base64 encoded ali access key secret, required if env SMS_ENABLED is true
|
||||
ali_access_key_secret: ""
|
||||
# base64 encoded ali sms sign name, required if env SMS_ENABLED is true
|
||||
ali_sms_sign_name: ""
|
||||
# base64 encoded ali sms template code, required if env SMS_ENABLED is true
|
||||
ali_sms_template_code: ""
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
kubectl apply -f manifests/deploy.yaml -f manifests/rbac.yaml -f manifests/ingress.yaml
|
||||
|
||||
secret_exists=$(kubectl get secret desktop-frontend-secret -n sealos --ignore-not-found=true)
|
||||
if [[ -n "$secret_exists" ]]; then
|
||||
echo "desktop-frontend-secret already exists, skip create desktop secret"
|
||||
cm_exists=$(kubectl get cm desktop-frontend-config -n sealos --ignore-not-found=true)
|
||||
if [[ -n "cm_exists" ]]; then
|
||||
echo "desktop-frontend-config already exists, skip create desktop config"
|
||||
else
|
||||
echo "create desktop secret"
|
||||
kubectl apply -f manifests/secret.yaml --validate=false
|
||||
echo "create desktop config"
|
||||
kubectl apply -f manifests/config.yaml --validate=false
|
||||
fi
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import request from '@/services/request';
|
||||
import { ApiResp, NotificationItem, Session, SystemConfigType, SystemEnv } from '@/types';
|
||||
import {
|
||||
ApiResp,
|
||||
NotificationItem,
|
||||
LayoutConfigType,
|
||||
CloudConfigType,
|
||||
AuthClientConfigType,
|
||||
AppClientConfigType,
|
||||
CommonConfigType,
|
||||
CommonClientConfigType
|
||||
} from '@/types';
|
||||
import { AccountCRD } from '@/types/user';
|
||||
|
||||
// handle baidu
|
||||
@@ -25,12 +34,24 @@ export const getUserAccount = () => {
|
||||
return request.get<AccountCRD>('/api/account/getAccount');
|
||||
};
|
||||
|
||||
export const getSystemEnv = () => {
|
||||
return request.get<SystemEnv>('/api/platform/getEnv');
|
||||
export const getAppConfig = () => {
|
||||
return request.get<AppClientConfigType>('/api/platform/getAppConfig');
|
||||
};
|
||||
|
||||
export const getSystemConfig = () => {
|
||||
return request.get<SystemConfigType>('/api/platform/getSystemConfig');
|
||||
export const getCloudConfig = () => {
|
||||
return request.get<CloudConfigType>('/api/platform/getCloudConfig');
|
||||
};
|
||||
|
||||
export const getCommonConfig = () => {
|
||||
return request.get<CommonClientConfigType>('/api/platform/getCommonConfig');
|
||||
};
|
||||
|
||||
export const getLayoutConfig = () => {
|
||||
return request.get<LayoutConfigType>('/api/platform/getLayoutConfig');
|
||||
};
|
||||
|
||||
export const getAuthConfig = () => {
|
||||
return request.get<AuthClientConfigType>('/api/platform/getAuthConfig');
|
||||
};
|
||||
|
||||
export const getPriceBonus = () => {
|
||||
|
||||
@@ -18,16 +18,17 @@ import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useMemo, useState } from 'react';
|
||||
import useAppStore from '@/stores/app';
|
||||
import { ApiResp, Region } from '@/types';
|
||||
import { ApiResp } from '@/types';
|
||||
import { formatMoney } from '@/utils/format';
|
||||
import PasswordModify from './PasswordModify';
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
import { CopyIcon, DownloadIcon, LogoutIcon, RightArrowIcon } from '@sealos/ui';
|
||||
import { ImageFallBackUrl } from '@/stores/config';
|
||||
import { CopyIcon, DownloadIcon, LogoutIcon } from '@sealos/ui';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
export default function Account({ disclosure }: { disclosure: UseDisclosureReturn }) {
|
||||
const [showId, setShowId] = useState(true);
|
||||
const { needPassword, rechargeEnabled } = useGlobalStore((state) => state.systemEnv);
|
||||
const passwordEnabled = useConfigStore().authConfig?.idp?.password?.enabled;
|
||||
const rechargeEnabled = useConfigStore().commonConfig?.rechargeEnabled;
|
||||
const logo = useConfigStore().layoutConfig?.logo;
|
||||
const router = useRouter();
|
||||
const { copyData } = useCopyData();
|
||||
const openApp = useAppStore((s) => s.openApp);
|
||||
@@ -94,7 +95,7 @@ export default function Account({ disclosure }: { disclosure: UseDisclosureRetur
|
||||
height={'80px'}
|
||||
borderRadius="full"
|
||||
src={user?.avatar}
|
||||
fallbackSrc={ImageFallBackUrl}
|
||||
fallbackSrc={logo}
|
||||
alt="user avator"
|
||||
/>
|
||||
<Text color={'#24282C'} fontSize={'20px'} fontWeight={600}>
|
||||
@@ -128,7 +129,7 @@ export default function Account({ disclosure }: { disclosure: UseDisclosureRetur
|
||||
fontSize={'13px'}
|
||||
gap={'0px'}
|
||||
>
|
||||
{needPassword && (
|
||||
{passwordEnabled && (
|
||||
<Flex
|
||||
justify={'space-between'}
|
||||
alignItems={'center'}
|
||||
|
||||
@@ -6,7 +6,7 @@ import React, { useRef, useState } from 'react';
|
||||
import Draggable, { DraggableEventHandler } from 'react-draggable';
|
||||
import styles from './index.module.scss';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { ImageFallBackUrl } from '@/stores/config';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
export default function AppWindow(props: {
|
||||
style?: React.CSSProperties;
|
||||
@@ -23,6 +23,7 @@ export default function AppWindow(props: {
|
||||
findAppInfoById,
|
||||
maxZIndex
|
||||
} = useAppStore();
|
||||
const logo = useConfigStore().layoutConfig?.logo;
|
||||
const { t, i18n } = useTranslation();
|
||||
const wnapp = findAppInfoById(pid);
|
||||
const [position, setPosition] = useState({ x: 0, y: 0 });
|
||||
@@ -111,7 +112,7 @@ export default function AppWindow(props: {
|
||||
<Flex ml="16px" alignItems={'center'} fontSize={'12px'} fontWeight={400}>
|
||||
<Image
|
||||
src={wnapp?.icon}
|
||||
fallbackSrc={ImageFallBackUrl}
|
||||
fallbackSrc={logo}
|
||||
alt={wnapp?.name}
|
||||
width={'20px'}
|
||||
height={'20px'}
|
||||
@@ -149,7 +150,7 @@ export default function AppWindow(props: {
|
||||
>
|
||||
<Image
|
||||
src="/icons/minimize.png"
|
||||
fallbackSrc={ImageFallBackUrl}
|
||||
fallbackSrc={logo}
|
||||
alt={wnapp?.name}
|
||||
width={'12px'}
|
||||
height={'12px'}
|
||||
@@ -170,7 +171,7 @@ export default function AppWindow(props: {
|
||||
>
|
||||
<Image
|
||||
src={wnapp.size === 'maximize' ? '/icons/maximize.png' : '/icons/maxmin.png'}
|
||||
fallbackSrc={ImageFallBackUrl}
|
||||
fallbackSrc={logo}
|
||||
alt={wnapp?.name}
|
||||
width={'12px'}
|
||||
height={'12px'}
|
||||
@@ -191,7 +192,7 @@ export default function AppWindow(props: {
|
||||
>
|
||||
<Image
|
||||
src={'/icons/close.png'}
|
||||
fallbackSrc={ImageFallBackUrl}
|
||||
fallbackSrc={logo}
|
||||
alt={wnapp?.name}
|
||||
width={'12px'}
|
||||
height={'12px'}
|
||||
|
||||
@@ -14,7 +14,7 @@ import styles from './index.module.scss';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getGlobalNotification } from '@/api/platform';
|
||||
import { useMessage } from '@sealos/ui';
|
||||
import { BackgroundImageUrl, ImageFallBackUrl } from '@/stores/config';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
const TimeComponent = dynamic(() => import('./time'), {
|
||||
ssr: false
|
||||
});
|
||||
@@ -22,6 +22,8 @@ const TimeComponent = dynamic(() => import('./time'), {
|
||||
export default function DesktopContent(props: any) {
|
||||
const { t, i18n } = useTranslation();
|
||||
const { installedApps: apps, runningInfo, openApp, setToHighestLayerById } = useAppStore();
|
||||
const backgroundImage = useConfigStore().layoutConfig?.backgroundImage;
|
||||
const logo = useConfigStore().layoutConfig?.logo;
|
||||
const renderApps = apps.filter((item: TApp) => item?.displayType === 'normal');
|
||||
const [maxItems, setMaxItems] = useState(10);
|
||||
const { message } = useMessage();
|
||||
@@ -109,7 +111,7 @@ export default function DesktopContent(props: any) {
|
||||
<Box
|
||||
id="desktop"
|
||||
className={styles.desktop}
|
||||
backgroundImage={`url(${BackgroundImageUrl})`}
|
||||
backgroundImage={`url(${backgroundImage || '/images/bg-blue.jpg'})`}
|
||||
backgroundRepeat={'no-repeat'}
|
||||
backgroundSize={'cover'}
|
||||
>
|
||||
@@ -166,7 +168,7 @@ export default function DesktopContent(props: any) {
|
||||
width="100%"
|
||||
height="100%"
|
||||
src={item?.icon}
|
||||
fallbackSrc={ImageFallBackUrl}
|
||||
fallbackSrc={logo || '/logo.svg'}
|
||||
draggable={false}
|
||||
alt="user avator"
|
||||
/>
|
||||
|
||||
@@ -7,7 +7,7 @@ import Iconfont from '../iconfont';
|
||||
import styles from './index.module.scss';
|
||||
import homeIcon from 'public/icons/home.svg';
|
||||
import { APPTYPE } from '@/types';
|
||||
import { ImageFallBackUrl } from '@/stores/config';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
enum Suction {
|
||||
None,
|
||||
@@ -54,6 +54,8 @@ export default function Index(props: any) {
|
||||
...runningInfo
|
||||
];
|
||||
|
||||
const logo = useConfigStore().layoutConfig?.logo;
|
||||
|
||||
const [degree, contentSkewDegree, contentRotateDegree] = useMemo(() => {
|
||||
const len = apps?.length < 6 ? 6 : apps?.length > 8 ? 8 : apps?.length;
|
||||
const temp: number = 360 / len;
|
||||
@@ -245,7 +247,7 @@ export default function Index(props: any) {
|
||||
>
|
||||
<Image
|
||||
src={item?.icon}
|
||||
fallbackSrc={ImageFallBackUrl}
|
||||
fallbackSrc={logo || '/logo.svg'}
|
||||
alt={item?.name}
|
||||
w="24px"
|
||||
h="24px"
|
||||
|
||||
@@ -7,7 +7,7 @@ import Iconfont from '../iconfont';
|
||||
import styles from './index.module.scss';
|
||||
import clsx from 'clsx';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { ImageFallBackUrl } from '@/stores/config';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
export default function Index() {
|
||||
const { t, i18n } = useTranslation();
|
||||
@@ -19,6 +19,7 @@ export default function Index() {
|
||||
const endIndex = startIndex + itemsPerPage;
|
||||
const paginatedApps = apps?.slice(startIndex, endIndex);
|
||||
const totalPages = Math.ceil((apps?.length || 0) / itemsPerPage);
|
||||
const logo = useConfigStore().layoutConfig?.logo;
|
||||
|
||||
const handleDoubleClick = (e: MouseEvent<HTMLDivElement>, item: TApp) => {
|
||||
e.preventDefault();
|
||||
@@ -104,7 +105,7 @@ export default function Index() {
|
||||
width="100%"
|
||||
height="100%"
|
||||
src={item?.icon}
|
||||
fallbackSrc={ImageFallBackUrl}
|
||||
fallbackSrc={logo || '/logo.svg'}
|
||||
draggable={false}
|
||||
alt="user avator"
|
||||
/>
|
||||
|
||||
@@ -1,133 +1,137 @@
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
import useSessionStore from '@/stores/session';
|
||||
import { OauthProvider } from '@/types/user';
|
||||
import { Button, Image, Flex, Icon, Center } from '@chakra-ui/react';
|
||||
import { GithubIcon, GoogleIcon, WechatIcon } from '@sealos/ui';
|
||||
import { useRouter } from 'next/router';
|
||||
import { MouseEventHandler } from 'react';
|
||||
import { MouseEventHandler, useMemo } from 'react';
|
||||
const AuthList = () => {
|
||||
const { systemEnv } = useGlobalStore();
|
||||
const {
|
||||
needGithub = false,
|
||||
needWechat = false,
|
||||
needGoogle = false,
|
||||
wechat_client_id = '',
|
||||
github_client_id = '',
|
||||
google_client_id = '',
|
||||
callback_url = '',
|
||||
// https://sealos.io/siginIn
|
||||
oauth_proxy = '',
|
||||
oauth2_client_id,
|
||||
oauth2_auth_url,
|
||||
needOAuth2 = false
|
||||
} = systemEnv ?? {};
|
||||
const oauthLogin = async ({ url, provider }: { url: string; provider?: OauthProvider }) => {
|
||||
setProvider(provider);
|
||||
window.location.href = url;
|
||||
};
|
||||
const conf = useConfigStore().authConfig;
|
||||
|
||||
const router = useRouter();
|
||||
const oauthProxyLogin = async ({
|
||||
state,
|
||||
provider,
|
||||
id
|
||||
}: {
|
||||
state: string;
|
||||
provider: OauthProvider;
|
||||
id: string;
|
||||
}) => {
|
||||
setProvider(provider);
|
||||
const target = new URL(oauth_proxy);
|
||||
const callback = new URL(callback_url);
|
||||
callback.searchParams.append('state', state);
|
||||
target.searchParams.append('oauthProxyState', callback.toString());
|
||||
target.searchParams.append('oauthProxyClientID', id);
|
||||
target.searchParams.append('oauthProxyProvider', provider);
|
||||
router.replace(target.toString());
|
||||
};
|
||||
|
||||
const logo = useConfigStore().layoutConfig?.logo;
|
||||
|
||||
const { generateState, setProvider } = useSessionStore();
|
||||
const authList: { icon: typeof Icon; cb: MouseEventHandler; need: boolean }[] = [
|
||||
{
|
||||
icon: GithubIcon,
|
||||
cb: (e) => {
|
||||
e.preventDefault();
|
||||
const state = generateState();
|
||||
if (oauth_proxy)
|
||||
oauthProxyLogin({
|
||||
provider: 'github',
|
||||
state,
|
||||
id: github_client_id
|
||||
});
|
||||
else
|
||||
oauthLogin({
|
||||
provider: 'github',
|
||||
url: `https://github.com/login/oauth/authorize?client_id=${github_client_id}&redirect_uri=${callback_url}&scope=user:email%20read:user&state=${state}`
|
||||
});
|
||||
const authList: { icon: typeof Icon; cb: MouseEventHandler; need: boolean }[] = useMemo(() => {
|
||||
if (!conf) return [];
|
||||
const oauthLogin = async ({ url, provider }: { url: string; provider?: OauthProvider }) => {
|
||||
setProvider(provider);
|
||||
window.location.href = url;
|
||||
};
|
||||
const oauthProxyLogin = async ({
|
||||
state,
|
||||
provider,
|
||||
id
|
||||
}: {
|
||||
state: string;
|
||||
provider: OauthProvider;
|
||||
id: string;
|
||||
}) => {
|
||||
// if(!conf) return
|
||||
setProvider(provider);
|
||||
const target = new URL(conf.proxyAddress);
|
||||
const callback = new URL(conf.callbackURL);
|
||||
callback.searchParams.append('state', state);
|
||||
target.searchParams.append('oauthProxyState', callback.toString());
|
||||
target.searchParams.append('oauthProxyClientID', id);
|
||||
target.searchParams.append('oauthProxyProvider', provider);
|
||||
router.replace(target.toString());
|
||||
};
|
||||
return [
|
||||
{
|
||||
icon: GithubIcon,
|
||||
cb: (e) => {
|
||||
e.preventDefault();
|
||||
const state = generateState();
|
||||
const githubConf = conf?.idp.github;
|
||||
if (conf?.proxyAddress)
|
||||
oauthProxyLogin({
|
||||
provider: 'github',
|
||||
state,
|
||||
id: githubConf?.clientID as string
|
||||
});
|
||||
else
|
||||
oauthLogin({
|
||||
provider: 'github',
|
||||
url: `https://github.com/login/oauth/authorize?client_id=${githubConf?.clientID}&redirect_uri=${conf?.callbackURL}&scope=user:email%20read:user&state=${state}`
|
||||
});
|
||||
},
|
||||
need: conf.idp.github.enabled
|
||||
},
|
||||
need: needGithub
|
||||
},
|
||||
{
|
||||
icon: WechatIcon,
|
||||
cb: (e) => {
|
||||
e.preventDefault();
|
||||
const state = generateState();
|
||||
if (oauth_proxy)
|
||||
oauthProxyLogin({
|
||||
provider: 'wechat',
|
||||
state,
|
||||
id: wechat_client_id
|
||||
});
|
||||
else
|
||||
oauthLogin({
|
||||
provider: 'wechat',
|
||||
url: `https://open.weixin.qq.com/connect/qrconnect?appid=${wechat_client_id}&redirect_uri=${callback_url}&response_type=code&state=${state}&scope=snsapi_login&#wechat_redirect`
|
||||
});
|
||||
{
|
||||
icon: WechatIcon,
|
||||
cb: (e) => {
|
||||
const wechatConf = conf?.idp.wechat;
|
||||
e.preventDefault();
|
||||
const state = generateState();
|
||||
if (conf.proxyAddress)
|
||||
oauthProxyLogin({
|
||||
provider: 'wechat',
|
||||
state,
|
||||
id: conf.idp.wechat?.clientID
|
||||
});
|
||||
else
|
||||
oauthLogin({
|
||||
provider: 'wechat',
|
||||
url: `https://open.weixin.qq.com/connect/qrconnect?appid=${wechatConf?.clientID}&redirect_uri=${conf?.callbackURL}&response_type=code&state=${state}&scope=snsapi_login&#wechat_redirect`
|
||||
});
|
||||
},
|
||||
need: conf?.idp.wechat?.enabled as boolean
|
||||
},
|
||||
need: needWechat
|
||||
},
|
||||
{
|
||||
icon: GoogleIcon,
|
||||
cb: (e) => {
|
||||
e.preventDefault();
|
||||
const state = generateState();
|
||||
const scope = encodeURIComponent(`https://www.googleapis.com/auth/userinfo.profile openid`);
|
||||
if (oauth_proxy)
|
||||
oauthProxyLogin({
|
||||
state,
|
||||
provider: 'google',
|
||||
id: google_client_id
|
||||
});
|
||||
else
|
||||
oauthLogin({
|
||||
provider: 'google',
|
||||
url: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${google_client_id}&redirect_uri=${callback_url}&response_type=code&state=${state}&scope=${scope}&include_granted_scopes=true`
|
||||
});
|
||||
{
|
||||
icon: GoogleIcon,
|
||||
cb: (e) => {
|
||||
e.preventDefault();
|
||||
const state = generateState();
|
||||
const googleConf = conf?.idp.google;
|
||||
const scope = encodeURIComponent(
|
||||
`https://www.googleapis.com/auth/userinfo.profile openid`
|
||||
);
|
||||
if (conf.proxyAddress)
|
||||
oauthProxyLogin({
|
||||
state,
|
||||
provider: 'google',
|
||||
id: googleConf?.clientID as string
|
||||
});
|
||||
else
|
||||
oauthLogin({
|
||||
provider: 'google',
|
||||
url: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${
|
||||
googleConf?.clientID as string
|
||||
}&redirect_uri=${
|
||||
conf?.callbackURL
|
||||
}&response_type=code&state=${state}&scope=${scope}&include_granted_scopes=true`
|
||||
});
|
||||
},
|
||||
need: conf.idp.google.enabled as boolean
|
||||
},
|
||||
need: needGoogle
|
||||
},
|
||||
{
|
||||
icon: () => (
|
||||
<Center>
|
||||
<Image alt="logo" width={'20px'} src="logo.svg"></Image>
|
||||
</Center>
|
||||
),
|
||||
cb: (e) => {
|
||||
e.preventDefault();
|
||||
const state = generateState();
|
||||
if (oauth_proxy)
|
||||
oauthProxyLogin({
|
||||
provider: 'oauth2',
|
||||
state,
|
||||
id: oauth2_client_id
|
||||
});
|
||||
else
|
||||
oauthLogin({
|
||||
provider: 'oauth2',
|
||||
url: `${oauth2_auth_url}?client_id=${oauth2_client_id}&redirect_uri=${callback_url}&response_type=code&state=${state}`
|
||||
});
|
||||
},
|
||||
need: needOAuth2
|
||||
}
|
||||
];
|
||||
{
|
||||
icon: () => (
|
||||
<Center>
|
||||
<Image alt="logo" width={'20px'} src={logo || '/logo.svg'}></Image>
|
||||
</Center>
|
||||
),
|
||||
cb: (e) => {
|
||||
e.preventDefault();
|
||||
const state = generateState();
|
||||
const oauth2Conf = conf?.idp.oauth2;
|
||||
if (conf.proxyAddress)
|
||||
oauthProxyLogin({
|
||||
provider: 'oauth2',
|
||||
state,
|
||||
id: oauth2Conf.clientID as string
|
||||
});
|
||||
else
|
||||
oauthLogin({
|
||||
provider: 'oauth2',
|
||||
url: `${oauth2Conf?.authURL}?client_id=${oauth2Conf.clientID}&redirect_uri=${oauth2Conf.callbackURL}&response_type=code&state=${state}`
|
||||
});
|
||||
},
|
||||
need: conf.idp.oauth2?.enabled as boolean
|
||||
}
|
||||
];
|
||||
}, [conf, generateState, logo, router, setProvider]);
|
||||
|
||||
return (
|
||||
<Flex gap={'14px'}>
|
||||
|
||||
@@ -5,8 +5,7 @@ import Language from '@/components/signin/auth/useLanguage';
|
||||
import usePassword from '@/components/signin/auth/usePassword';
|
||||
import useProtocol from '@/components/signin/auth/useProtocol';
|
||||
import useSms from '@/components/signin/auth/useSms';
|
||||
import { BackgroundImageUrl, useSystemConfigStore } from '@/stores/config';
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
import useSessionStore from '@/stores/session';
|
||||
import { LoginType } from '@/types';
|
||||
import {
|
||||
@@ -30,20 +29,10 @@ import useWechat from './auth/useWechat';
|
||||
import { Turnstile, TurnstileInstance } from '@marsidev/react-turnstile';
|
||||
|
||||
export default function SigninComponent() {
|
||||
const platformEnv = useGlobalStore((state) => state.systemEnv);
|
||||
|
||||
const { systemConfig } = useSystemConfigStore();
|
||||
const {
|
||||
service_protocol_zh = '',
|
||||
private_protocol_zh = '',
|
||||
service_protocol_en = '',
|
||||
private_protocol_en = '',
|
||||
needPassword = false,
|
||||
needSms = false,
|
||||
openWechatEnabled = false,
|
||||
cf_sitekey
|
||||
} = platformEnv || {};
|
||||
const needTabs = needPassword && needSms;
|
||||
const conf = useConfigStore();
|
||||
const needPassword = conf.authConfig?.idp.password?.enabled;
|
||||
const needSms = conf.authConfig?.idp.sms?.enabled;
|
||||
const needTabs = conf.authConfig?.idp.password?.enabled && conf.authConfig?.idp.sms?.enabled;
|
||||
const disclosure = useDisclosure();
|
||||
const { t, i18n } = useTranslation();
|
||||
const [tabIndex, setTabIndex] = useState<LoginType>(LoginType.NONE);
|
||||
@@ -52,13 +41,13 @@ export default function SigninComponent() {
|
||||
let protocol_data: Parameters<typeof useProtocol>[0];
|
||||
if (['zh', 'zh-Hans'].includes(i18n.language))
|
||||
protocol_data = {
|
||||
service_protocol: service_protocol_zh,
|
||||
private_protocol: private_protocol_zh
|
||||
service_protocol: conf.layoutConfig?.protocol?.serviceProtocol.zh as string,
|
||||
private_protocol: conf.layoutConfig?.protocol?.privateProtocol.zh as string
|
||||
};
|
||||
else
|
||||
protocol_data = {
|
||||
service_protocol: service_protocol_en,
|
||||
private_protocol: private_protocol_en
|
||||
service_protocol: conf.layoutConfig?.protocol?.serviceProtocol.en as string,
|
||||
private_protocol: conf.layoutConfig?.protocol?.privateProtocol.en as string
|
||||
};
|
||||
const { Protocol, isAgree, setIsInvalid } = useProtocol(protocol_data!);
|
||||
const { WechatComponent, login: wechatSubmit } = useWechat();
|
||||
@@ -146,20 +135,19 @@ export default function SigninComponent() {
|
||||
showError(t('Read and agree'));
|
||||
}
|
||||
}, 500);
|
||||
|
||||
return (
|
||||
<Box
|
||||
position={'relative'}
|
||||
overflow={'hidden'}
|
||||
w="100vw"
|
||||
h="100vh"
|
||||
backgroundImage={`url(${BackgroundImageUrl})`}
|
||||
backgroundImage={`url(${conf.layoutConfig?.backgroundImage || ''})`}
|
||||
backgroundRepeat={'no-repeat'}
|
||||
backgroundSize={'cover'}
|
||||
>
|
||||
<Head>
|
||||
<title>{systemConfig?.metaTitle}</title>
|
||||
<meta name="description" content={systemConfig?.metaDescription} />
|
||||
<title>{conf.layoutConfig?.meta.title || ''}</title>
|
||||
<meta name="description" content={conf.layoutConfig?.meta.description} />
|
||||
</Head>
|
||||
<Flex h="full" w="full" flexDir={'column'} justifyContent={'center'} alignItems={'center'}>
|
||||
<Box mb="36px">
|
||||
@@ -169,7 +157,7 @@ export default function SigninComponent() {
|
||||
fontWeight={700}
|
||||
textShadow={'0px 2px 6px rgba(0, 0, 0, 0.30)'}
|
||||
>
|
||||
{systemConfig?.title}
|
||||
{conf.layoutConfig?.title}
|
||||
</Text>
|
||||
</Box>
|
||||
<Flex
|
||||
@@ -212,7 +200,7 @@ export default function SigninComponent() {
|
||||
<Tab px="0" _selected={{ color: 'white' }}>
|
||||
{t('Password Login')}
|
||||
</Tab>
|
||||
{openWechatEnabled && (
|
||||
{conf.authConfig?.idp.wechat.enabled && (
|
||||
<Tab px="0" _selected={{ color: 'white' }}>
|
||||
{t('Official account login')}
|
||||
</Tab>
|
||||
@@ -227,13 +215,13 @@ export default function SigninComponent() {
|
||||
{tabIndex !== LoginType.WeChat && (
|
||||
<>
|
||||
<Protocol />
|
||||
{!!cf_sitekey && (
|
||||
{!!conf.commonConfig?.cfSiteKey && (
|
||||
<Turnstile
|
||||
options={{
|
||||
size: 'invisible'
|
||||
}}
|
||||
ref={turnstileRef}
|
||||
siteKey={cf_sitekey}
|
||||
siteKey={conf.commonConfig?.cfSiteKey}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
|
||||
@@ -25,6 +25,7 @@ import { useCustomToast } from '@/hooks/useCustomToast';
|
||||
import { ApiResp } from '@/types';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { ExchangeIcon, ExpanMoreIcon } from '@sealos/ui';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
export default function Abdication({
|
||||
ns_uid,
|
||||
@@ -34,6 +35,7 @@ export default function Abdication({
|
||||
users: TeamUserDto[];
|
||||
ns_uid: string;
|
||||
} & ButtonProps) {
|
||||
const logo = useConfigStore().layoutConfig?.logo;
|
||||
const { t } = useTranslation();
|
||||
const { onOpen, isOpen, onClose } = useDisclosure();
|
||||
const queryClient = useQueryClient();
|
||||
@@ -113,7 +115,7 @@ export default function Abdication({
|
||||
<Image
|
||||
alt="avatar"
|
||||
src={targetUser.avatar}
|
||||
fallbackSrc={'/logo.svg'}
|
||||
fallbackSrc={logo || '/logo.svg'}
|
||||
boxSize={'24px'}
|
||||
borderRadius={'50%'}
|
||||
mr="8px"
|
||||
@@ -141,7 +143,7 @@ export default function Abdication({
|
||||
<Image
|
||||
alt="logo"
|
||||
src={user.avatarUrl}
|
||||
fallbackSrc={'/logo.svg'}
|
||||
fallbackSrc={logo || '/logo.svg'}
|
||||
boxSize={'24px'}
|
||||
borderRadius={'50%'}
|
||||
mr="8px"
|
||||
|
||||
@@ -19,6 +19,7 @@ import RemoveMember from './RemoveMember';
|
||||
import Abdication from './Abdication';
|
||||
import ModifyRole from './ModifyRole';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
export default function UserTable({
|
||||
users = [],
|
||||
|
||||
@@ -5,8 +5,8 @@ import { Box, Center, Flex, FlexProps, Image, useDisclosure } from '@chakra-ui/r
|
||||
import LangSelectSimple from '../LangSelect/simple';
|
||||
import Iconfont from '../iconfont';
|
||||
import GithubComponent from './github';
|
||||
import { ImageFallBackUrl, useSystemConfigStore } from '@/stores/config';
|
||||
import { ReactElement, useCallback, useState } from 'react';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
import RegionToggle from '@/components/region/RegionToggle';
|
||||
import WorkspaceToggle from '@/components/team/WorkspaceToggle';
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function Index(props: { userMenuStyleProps?: FlexProps }) {
|
||||
const accountDisclosure = useDisclosure();
|
||||
const showDisclosure = useDisclosure();
|
||||
|
||||
const { systemConfig } = useSystemConfigStore();
|
||||
const { layoutConfig } = useConfigStore();
|
||||
const userInfo = useSessionStore((state) => state.session);
|
||||
const onAmount = useCallback((amount: number) => setNotificationAmount(amount), []);
|
||||
const {
|
||||
@@ -64,7 +64,7 @@ export default function Index(props: { userMenuStyleProps?: FlexProps }) {
|
||||
height={'36px'}
|
||||
borderRadius="full"
|
||||
src={userInfo?.user?.avatar || ''}
|
||||
fallbackSrc={ImageFallBackUrl}
|
||||
fallbackSrc={layoutConfig?.logo}
|
||||
alt="user avator"
|
||||
/>
|
||||
),
|
||||
@@ -77,7 +77,7 @@ export default function Index(props: { userMenuStyleProps?: FlexProps }) {
|
||||
<RegionToggle />
|
||||
<WorkspaceToggle />
|
||||
<LangSelectSimple {...baseItemStyle} />
|
||||
{systemConfig?.showGithubStar && <GithubComponent {...baseItemStyle} />}
|
||||
{layoutConfig?.common.githubStarEnabled && <GithubComponent {...baseItemStyle} />}
|
||||
{buttonList.map((item) => (
|
||||
<Flex
|
||||
key={item.key}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { getPriceBonus, getUserAccount, updateDesktopGuide } from '@/api/platform';
|
||||
import { GUIDE_DESKTOP_INDEX_KEY } from '@/constants/account';
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
import { formatMoney } from '@/utils/format';
|
||||
import { Box, Button, Flex, FlexProps, Icon, Image, Text } from '@chakra-ui/react';
|
||||
import { driver } from '@sealos/driver';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
export function DriverStarIcon() {
|
||||
return (
|
||||
@@ -47,7 +47,7 @@ export default function useDriver({ openDesktopApp }: { openDesktopApp: any }) {
|
||||
const [giftAmount, setGiftAmount] = useState(8);
|
||||
const router = useRouter();
|
||||
|
||||
const { systemEnv } = useGlobalStore();
|
||||
const conf = useConfigStore().commonConfig;
|
||||
const handleSkipGuide = () => {
|
||||
setShowGuide(false);
|
||||
updateDesktopGuide().catch((err) => {
|
||||
@@ -58,7 +58,7 @@ export default function useDriver({ openDesktopApp }: { openDesktopApp: any }) {
|
||||
useEffect(() => {
|
||||
const handleUserGuide = async () => {
|
||||
try {
|
||||
if (!systemEnv.guideEnabled) return;
|
||||
if (!conf?.guideEnabled) return;
|
||||
const { data } = await getUserAccount();
|
||||
const bonus = await getPriceBonus();
|
||||
if (bonus.data?.activities) {
|
||||
@@ -75,9 +75,9 @@ export default function useDriver({ openDesktopApp }: { openDesktopApp: any }) {
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
systemEnv?.guideEnabled && handleUserGuide();
|
||||
conf?.guideEnabled && handleUserGuide();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [systemEnv]);
|
||||
}, [conf]);
|
||||
|
||||
const PopoverBodyInfo = (props: FlexProps) => (
|
||||
<Flex
|
||||
|
||||
@@ -13,15 +13,16 @@ import {
|
||||
import useCallbackStore from '@/stores/callback';
|
||||
import { useEffect } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { ImageFallBackUrl } from '@/stores/config';
|
||||
import { ROLE_LIST } from '@/types/team';
|
||||
import { compareFirstLanguages } from '@/utils/tools';
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
const Callback: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { token: curToken, session } = useSessionStore((s) => s);
|
||||
const { lastWorkSpaceId } = useSessionStore();
|
||||
const logo = useConfigStore().layoutConfig?.logo;
|
||||
const { setWorkspaceInviteCode } = useCallbackStore();
|
||||
const { t } = useTranslation();
|
||||
const verifyMutation = useMutation({
|
||||
@@ -113,7 +114,7 @@ const Callback: NextPage = () => {
|
||||
gap={'8px'}
|
||||
>
|
||||
{' '}
|
||||
<Image boxSize={'34px'} borderRadius="full" src={ImageFallBackUrl} alt="logo" />
|
||||
<Image boxSize={'34px'} borderRadius="full" src={logo} alt="logo" />
|
||||
<Text fontWeight={700} fontSize={'24px'}>
|
||||
Sealos
|
||||
</Text>
|
||||
|
||||
@@ -10,8 +10,7 @@ import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
import '@sealos/driver/src/driver.css';
|
||||
import { useEffect } from 'react';
|
||||
import { useSystemConfigStore } from '@/stores/config';
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
@@ -30,12 +29,10 @@ Router.events.on('routeChangeError', () => NProgress.done());
|
||||
|
||||
const App = ({ Component, pageProps }: AppProps) => {
|
||||
const { i18n } = useTranslation();
|
||||
const { initSystemConfig } = useSystemConfigStore();
|
||||
const { initSystemEnv } = useGlobalStore();
|
||||
const { initAppConfig } = useConfigStore();
|
||||
|
||||
useEffect(() => {
|
||||
initSystemConfig();
|
||||
initSystemEnv();
|
||||
initAppConfig();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
|
||||
const clientId = process.env.GITHUB_CLIENT_ID!;
|
||||
const clientSecret = process.env.GITHUB_CLIENT_SECRET!;
|
||||
const clientId = global.AppConfig?.desktop.auth.idp.github?.clientID!;
|
||||
const clientSecret = global.AppConfig?.desktop.auth.idp.github?.clientSecret!;
|
||||
import { TgithubToken, TgithubUser } from '@/types/user';
|
||||
|
||||
import { enableGithub } from '@/services/enable';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
const clientId = process.env.GOOGLE_CLIENT_ID!;
|
||||
const clientSecret = process.env.GOOGLE_CLIENT_SECRET!;
|
||||
const callbackUrl = process.env.CALLBACK_URL || '';
|
||||
const clientId = global.AppConfig?.desktop.auth.idp.google?.clientID!;
|
||||
const clientSecret = global.AppConfig?.desktop.auth.idp.google?.clientSecret!;
|
||||
const callbackUrl = global.AppConfig?.desktop.auth.callbackURL || '';
|
||||
import * as jwt from 'jsonwebtoken';
|
||||
import { enableGoogle } from '@/services/enable';
|
||||
import { getBase64FromRemote } from '@/utils/tools';
|
||||
|
||||
@@ -7,11 +7,11 @@ import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { ProviderType } from 'prisma/global/generated/client';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 12);
|
||||
|
||||
const clientId = process.env.OAUTH2_CLIENT_ID!;
|
||||
const clientSecret = process.env.OAUTH2_CLIENT_SECRET!;
|
||||
const tokenUrl = process.env.OAUTH2_TOKEN_URL;
|
||||
const userInfoUrl = process.env.OAUTH2_USERINFO_URL;
|
||||
const redirectUrl = process.env.CALLBACK_URL;
|
||||
const clientId = global.AppConfig?.desktop.auth.idp.oauth2?.clientID!;
|
||||
const clientSecret = global.AppConfig?.desktop.auth.idp.oauth2?.clientSecret!;
|
||||
const tokenUrl = global.AppConfig?.desktop.auth.idp.oauth2?.tokenURL;
|
||||
const userInfoUrl = global.AppConfig?.desktop.auth.idp.oauth2?.userInfoURL;
|
||||
const redirectUrl = global.AppConfig?.desktop.auth.callbackURL;
|
||||
|
||||
//OAuth2 Support client_secret_post method to obtain token
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
|
||||
const APP_ID = process.env.WECHAT_CLIENT_ID!;
|
||||
const APP_SECRET = process.env.WECHAT_CLIENT_SECRET!;
|
||||
const APP_ID = global.AppConfig?.desktop.auth.idp.wechat?.clientID!;
|
||||
const APP_SECRET = global.AppConfig?.desktop.auth.idp.wechat?.clientSecret!;
|
||||
import { TWechatToken, TWechatUser } from '@/types/user';
|
||||
import { enableWechat } from '@/services/enable';
|
||||
import { getGlobalToken } from '@/services/backend/globalAuth';
|
||||
|
||||
@@ -11,12 +11,12 @@ import { addOrUpdateCode, checkSendable } from '@/services/backend/db/verifyCode
|
||||
import { enableSms } from '@/services/enable';
|
||||
import { retrySerially } from '@/utils/tools';
|
||||
|
||||
const accessKeyId = process.env.ALI_ACCESS_KEY_ID;
|
||||
const accessKeySecret = process.env.ALI_ACCESS_KEY_SECRET;
|
||||
const templateCode = process.env.ALI_TEMPLATE_CODE;
|
||||
const signName = process.env.ALI_SIGN_NAME;
|
||||
const verifyEndpoint = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
|
||||
const secret = process.env.CF_SECRET_KEY;
|
||||
const accessKeyId = global.AppConfig?.desktop.auth.idp.sms?.ali?.accessKeyID!;
|
||||
const accessKeySecret = global.AppConfig?.desktop.auth.idp.sms?.ali?.accessKeySecret!;
|
||||
const templateCode = global.AppConfig?.desktop.auth.idp.sms?.ali?.templateCode!;
|
||||
const signName = global.AppConfig?.desktop.auth.idp.sms?.ali?.signName!;
|
||||
const cfSiteKey = global.AppConfig?.common.cfSiteKey!;
|
||||
const cfVerifyEndpoint = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
if (!enableSms()) {
|
||||
@@ -24,15 +24,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
}
|
||||
const { phoneNumbers, cfToken } = req.body as { phoneNumbers?: string; cfToken?: string };
|
||||
|
||||
if (secret) {
|
||||
if (cfSiteKey) {
|
||||
if (!cfToken)
|
||||
return jsonRes(res, {
|
||||
message: 'cfToken is invalid',
|
||||
code: 400
|
||||
});
|
||||
const verifyRes = await fetch(verifyEndpoint, {
|
||||
const verifyRes = await fetch(cfVerifyEndpoint, {
|
||||
method: 'POST',
|
||||
body: `secret=${encodeURIComponent(secret)}&response=${encodeURIComponent(cfToken)}`,
|
||||
body: `secret=${encodeURIComponent(cfSiteKey)}&response=${encodeURIComponent(cfToken)}`,
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import {
|
||||
AppClientConfigType,
|
||||
AuthClientConfigType,
|
||||
CloudConfigType,
|
||||
CommonClientConfigType,
|
||||
DefaultAppClientConfig,
|
||||
LayoutConfigType
|
||||
} from '@/types/system';
|
||||
import { getCloudConfig } from '@/pages/api/platform/getCloudConfig';
|
||||
import { getAuthClientConfig } from '@/pages/api/platform/getAuthConfig';
|
||||
import { getLayoutConfig } from '@/pages/api/platform/getLayoutConfig';
|
||||
import { getCommonClientConfig } from './getCommonConfig';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const config = await getAppConfig();
|
||||
jsonRes(res, {
|
||||
data: config,
|
||||
code: 200
|
||||
});
|
||||
}
|
||||
|
||||
function genResConfig(
|
||||
cloudConf: CloudConfigType,
|
||||
authConf: AuthClientConfigType,
|
||||
commonConf: CommonClientConfigType,
|
||||
layoutConf: LayoutConfigType
|
||||
): AppClientConfigType {
|
||||
return {
|
||||
cloud: cloudConf,
|
||||
common: commonConf,
|
||||
desktop: {
|
||||
auth: authConf,
|
||||
layout: layoutConf
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function getAppConfig(): Promise<AppClientConfigType> {
|
||||
try {
|
||||
const cloudConf = await getCloudConfig();
|
||||
const authConf = await getAuthClientConfig();
|
||||
const commonConf = await getCommonClientConfig();
|
||||
const layoutConf = await getLayoutConfig();
|
||||
const conf = genResConfig(cloudConf, authConf, commonConf, layoutConf);
|
||||
return conf;
|
||||
} catch (error) {
|
||||
console.log('-getAppConfig-', error);
|
||||
return DefaultAppClientConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
import {
|
||||
AppConfigType,
|
||||
DefaultAuthClientConfig,
|
||||
AuthConfigType,
|
||||
AuthClientConfigType
|
||||
} from '@/types/system';
|
||||
import { readFileSync } from 'fs';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const config = await getAuthClientConfig();
|
||||
jsonRes(res, {
|
||||
data: config,
|
||||
code: 200
|
||||
});
|
||||
}
|
||||
|
||||
// genResAuthConfig Return AuthConfigType with only necessary fields for response to client, to avoid exposing sensitive data
|
||||
function genResAuthClientConfig(conf: AuthConfigType) {
|
||||
const authClientConfig: AuthClientConfigType = {
|
||||
callbackURL: conf.callbackURL || '',
|
||||
invite: {
|
||||
enabled: !!conf.invite?.enabled
|
||||
},
|
||||
idp: {
|
||||
password: {
|
||||
enabled: !!conf.idp.password?.enabled
|
||||
},
|
||||
sms: {
|
||||
enabled: !!conf.idp.sms?.enabled
|
||||
},
|
||||
github: {
|
||||
enabled: !!conf.idp.github?.enabled,
|
||||
clientID: conf.idp.github?.clientID || ''
|
||||
},
|
||||
wechat: {
|
||||
enabled: !!conf.idp.wechat?.enabled,
|
||||
clientID: conf.idp.wechat?.clientID || ''
|
||||
},
|
||||
google: {
|
||||
enabled: !!conf.idp.google?.enabled,
|
||||
clientID: conf.idp.google?.clientID || ''
|
||||
},
|
||||
oauth2: {
|
||||
enabled: !!conf.idp.oauth2?.enabled,
|
||||
callbackURL: conf.idp.oauth2?.callbackURL || '',
|
||||
clientID: conf.idp.oauth2?.clientID || '',
|
||||
authURL: conf.idp.oauth2?.authURL || '',
|
||||
tokenURL: conf.idp.oauth2?.tokenURL || '',
|
||||
userInfoURL: conf.idp.oauth2?.userInfoURL || ''
|
||||
}
|
||||
},
|
||||
proxyAddress: conf.proxyAddress || '',
|
||||
baiduToken: conf.baiduToken || ''
|
||||
};
|
||||
return authClientConfig;
|
||||
}
|
||||
|
||||
export async function getAuthClientConfig(): Promise<AuthClientConfigType> {
|
||||
try {
|
||||
if (!global.AppConfig) {
|
||||
const filename =
|
||||
process.env.NODE_ENV === 'development' ? 'data/config.yaml.local' : '/app/data/config.yaml';
|
||||
global.AppConfig = yaml.load(readFileSync(filename, 'utf-8')) as AppConfigType;
|
||||
}
|
||||
return genResAuthClientConfig(global.AppConfig.desktop.auth);
|
||||
} catch (error) {
|
||||
console.log('-getAuthConfig-', error);
|
||||
return DefaultAuthClientConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
import { AppConfigType, CloudConfigType, DefaultCloudConfig } from '@/types/system';
|
||||
import { readFileSync } from 'fs';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import yaml from 'js-yaml';
|
||||
import process from 'process';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const config = await getCloudConfig();
|
||||
jsonRes(res, {
|
||||
data: config,
|
||||
code: 200
|
||||
});
|
||||
}
|
||||
|
||||
function genResCloudConfig(conf: CloudConfigType): CloudConfigType {
|
||||
return {
|
||||
domain: conf.domain,
|
||||
port: conf.port
|
||||
} as CloudConfigType;
|
||||
}
|
||||
|
||||
export async function getCloudConfig(): Promise<CloudConfigType> {
|
||||
try {
|
||||
if (!global.AppConfig) {
|
||||
const filename =
|
||||
process.env.NODE_ENV === 'development'
|
||||
? process.env.CONFIG_PATH || 'data/config.yaml.local'
|
||||
: '/app/data/config.yaml';
|
||||
global.AppConfig = yaml.load(readFileSync(filename, 'utf-8')) as AppConfigType;
|
||||
}
|
||||
return genResCloudConfig(global.AppConfig.cloud) || DefaultCloudConfig;
|
||||
} catch (error) {
|
||||
console.log('-getAppConfig-', error);
|
||||
return DefaultCloudConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
import {
|
||||
AppConfigType,
|
||||
CommonClientConfigType,
|
||||
CommonConfigType,
|
||||
DefaultCommonClientConfig
|
||||
} from '@/types/system';
|
||||
import { readFileSync } from 'fs';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const config = await getCommonClientConfig();
|
||||
jsonRes(res, {
|
||||
data: config,
|
||||
code: 200
|
||||
});
|
||||
}
|
||||
function genResCommonClientConfig(common: CommonConfigType): CommonClientConfigType {
|
||||
return {
|
||||
guideEnabled: !!common.guideEnabled,
|
||||
rechargeEnabled: !!common.rechargeEnabled,
|
||||
cfSiteKey: common.cfSiteKey || ''
|
||||
};
|
||||
}
|
||||
export async function getCommonClientConfig(): Promise<CommonClientConfigType> {
|
||||
try {
|
||||
if (!global.AppConfig) {
|
||||
const filename =
|
||||
process.env.NODE_ENV === 'development' ? 'data/config.yaml.local' : '/app/data/config.yaml';
|
||||
global.AppConfig = yaml.load(readFileSync(filename, 'utf-8')) as AppConfigType;
|
||||
}
|
||||
return genResCommonClientConfig(global.AppConfig.common);
|
||||
} catch (error) {
|
||||
console.log('-getLayoutConfig-', error);
|
||||
return DefaultCommonClientConfig;
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
import {
|
||||
enableGithub,
|
||||
enableWechat,
|
||||
enablePassword,
|
||||
enableSms,
|
||||
enableGoogle,
|
||||
enableWechatRecharge,
|
||||
enableLicense,
|
||||
enableRecharge,
|
||||
enableOpenWechat,
|
||||
enableOAuth2
|
||||
} from '@/services/enable';
|
||||
import { SystemEnv } from '@/types';
|
||||
|
||||
export default async function handler(_: NextApiRequest, res: NextApiResponse) {
|
||||
const wechat_client_id = process.env.WECHAT_CLIENT_ID || '';
|
||||
const github_client_id = process.env.GITHUB_CLIENT_ID || '';
|
||||
const google_client_id = process.env.GOOGLE_CLIENT_ID || '';
|
||||
const service_protocol_zh = process.env.SERVICE_PROTOCOL_ZH || '';
|
||||
const private_protocol_zh = process.env.PRIVATE_PROTOCOL_ZH || '';
|
||||
const service_protocol_en = process.env.SERVICE_PROTOCOL_EN || '';
|
||||
const private_protocol_en = process.env.PRIVATE_PROTOCOL_EN || '';
|
||||
const oauth_proxy = process.env.OAUTH_PROXY || '';
|
||||
const callback_url = process.env.CALLBACK_URL || '';
|
||||
const cf_sitekey = process.env.CF_SITE_KEY || '';
|
||||
const needGithub = enableGithub();
|
||||
const needWechat = enableWechat();
|
||||
const needPassword = enablePassword();
|
||||
const needSms = enableSms();
|
||||
const needGoogle = enableGoogle();
|
||||
const wechatEnabledRecharge = enableWechatRecharge();
|
||||
const licenseEnabled = enableLicense();
|
||||
const rechargeEnabled = enableRecharge();
|
||||
const guideEnabled = process.env.GUIDE_ENABLED === 'true';
|
||||
const openWechatEnabled = enableOpenWechat();
|
||||
const oauth2_client_id = process.env.OAUTH2_CLIENT_ID || '';
|
||||
const oauth2_auth_url = process.env.OAUTH2_AUTH_URL || '';
|
||||
const needOAuth2 = enableOAuth2();
|
||||
|
||||
return jsonRes<SystemEnv>(res, {
|
||||
data: {
|
||||
SEALOS_CLOUD_DOMAIN: process.env.SEALOS_CLOUD_DOMAIN || 'cloud.sealos.io',
|
||||
wechat_client_id,
|
||||
github_client_id,
|
||||
google_client_id,
|
||||
oauth_proxy,
|
||||
callback_url,
|
||||
service_protocol_zh,
|
||||
private_protocol_zh,
|
||||
service_protocol_en,
|
||||
private_protocol_en,
|
||||
needPassword,
|
||||
needSms,
|
||||
needGithub,
|
||||
needWechat,
|
||||
needGoogle,
|
||||
wechatEnabledRecharge,
|
||||
rechargeEnabled,
|
||||
licenseEnabled,
|
||||
guideEnabled,
|
||||
openWechatEnabled,
|
||||
cf_sitekey,
|
||||
oauth2_client_id,
|
||||
oauth2_auth_url,
|
||||
needOAuth2
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
import { AppConfigType, DefaultLayoutConfig, LayoutConfigType } from '@/types/system';
|
||||
import { readFileSync } from 'fs';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const config = await getLayoutConfig();
|
||||
jsonRes(res, {
|
||||
data: config,
|
||||
code: 200
|
||||
});
|
||||
}
|
||||
|
||||
export async function getLayoutConfig(): Promise<LayoutConfigType> {
|
||||
try {
|
||||
if (!global.AppConfig) {
|
||||
const filename =
|
||||
process.env.NODE_ENV === 'development' ? 'data/config.yaml.local' : '/app/data/config.yaml';
|
||||
global.AppConfig = yaml.load(readFileSync(filename, 'utf-8')) as AppConfigType;
|
||||
}
|
||||
return global.AppConfig.desktop.layout || DefaultLayoutConfig;
|
||||
} catch (error) {
|
||||
console.log('-getLayoutConfig-', error);
|
||||
return DefaultLayoutConfig;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { jsonRes } from '@/services/backend/response';
|
||||
import { SystemConfigType } from '@/types/system';
|
||||
import { readFileSync } from 'fs';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const config = await getSystemConfig();
|
||||
jsonRes(res, {
|
||||
data: config,
|
||||
code: 200
|
||||
});
|
||||
}
|
||||
|
||||
const defaultConfig: SystemConfigType = {
|
||||
scripts: [],
|
||||
backgroundImageUrl: '/images/bg-blue.svg',
|
||||
imageFallBackUrl: 'logo.svg',
|
||||
title: 'Sealos',
|
||||
metaTitle: 'Sealos Cloud',
|
||||
metaDescription: 'sealos cloud dashboard',
|
||||
showGithubStar: true,
|
||||
isSystemConfigEnabled: true
|
||||
};
|
||||
|
||||
export async function getSystemConfig(): Promise<SystemConfigType> {
|
||||
try {
|
||||
const filename =
|
||||
process.env.NODE_ENV === 'development' ? 'data/config.local.json' : '/app/data/config.json';
|
||||
const res = JSON.parse(readFileSync(filename, 'utf-8')) as SystemConfigType;
|
||||
return res?.isSystemConfigEnabled ? res : defaultConfig;
|
||||
} catch (error) {
|
||||
console.log('-getSystemConfig-\n', error);
|
||||
return defaultConfig;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
bd_vid: string;
|
||||
main_url: string;
|
||||
};
|
||||
const BD_TOKEN = process.env.BD_TOKEN;
|
||||
const BD_TOKEN = global.AppConfig?.desktop.auth?.baiduToken;
|
||||
|
||||
if (!BD_TOKEN || !bd_vid) {
|
||||
return jsonRes(res, {
|
||||
|
||||
@@ -2,7 +2,7 @@ import DesktopContent from '@/components/desktop_content';
|
||||
import FloatButton from '@/components/floating_button';
|
||||
import MoreApps from '@/components/more_apps';
|
||||
import useAppStore from '@/stores/app';
|
||||
import { useSystemConfigStore } from '@/stores/config';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
import useSessionStore from '@/stores/session';
|
||||
import { parseOpenappQuery } from '@/utils/format';
|
||||
import { setInviterId } from '@/utils/sessionConfig';
|
||||
@@ -27,8 +27,9 @@ export default function Home({ sealos_cloud_domain }: { sealos_cloud_domain: str
|
||||
const { colorMode, toggleColorMode } = useColorMode();
|
||||
const init = useAppStore((state) => state.init);
|
||||
const setAutoLaunch = useAppStore((state) => state.setAutoLaunch);
|
||||
const { systemConfig } = useSystemConfigStore();
|
||||
const { layoutConfig } = useConfigStore();
|
||||
const { workspaceInviteCode, setWorkspaceInviteCode } = useCallbackStore();
|
||||
|
||||
useEffect(() => {
|
||||
colorMode === 'dark' ? toggleColorMode() : null;
|
||||
}, [colorMode, toggleColorMode]);
|
||||
@@ -96,13 +97,14 @@ export default function Home({ sealos_cloud_domain }: { sealos_cloud_domain: str
|
||||
return;
|
||||
}
|
||||
}, [workspaceInviteCode]);
|
||||
|
||||
return (
|
||||
<Box position={'relative'} overflow={'hidden'} w="100vw" h="100vh">
|
||||
<Head>
|
||||
<title>{systemConfig?.metaTitle}</title>
|
||||
<meta name="description" content={systemConfig?.metaTitle} />
|
||||
<title>{layoutConfig?.meta.title}</title>
|
||||
<meta name="description" content={layoutConfig?.meta.description} />
|
||||
</Head>
|
||||
{systemConfig?.scripts?.map((item, i) => {
|
||||
{layoutConfig?.meta.scripts?.map((item, i) => {
|
||||
return <Script key={i} {...item} />;
|
||||
})}
|
||||
<MoreAppsContext.Provider value={{ showMoreApps, setShowMoreApps }}>
|
||||
@@ -114,11 +116,12 @@ export default function Home({ sealos_cloud_domain }: { sealos_cloud_domain: str
|
||||
);
|
||||
}
|
||||
|
||||
export async function getServerSideProps({ req, res, locales, query }: any) {
|
||||
export async function getServerSideProps({ req, res, locales }: any) {
|
||||
const local =
|
||||
req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh');
|
||||
res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`);
|
||||
const sealos_cloud_domain = process.env.SEALOS_CLOUD_DOMAIN || 'cloud.sealos.io';
|
||||
|
||||
const sealos_cloud_domain = global.AppConfig?.cloud.domain || 'cloud.sealos.io';
|
||||
|
||||
return {
|
||||
props: {
|
||||
|
||||
@@ -2,22 +2,24 @@ import { useRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
import request from '@/services/request';
|
||||
import useSessionStore from '@/stores/session';
|
||||
import { ApiResp, SystemEnv } from '@/types';
|
||||
import { ApiResp, AuthConfigType } from '@/types';
|
||||
import { Flex, Spinner } from '@chakra-ui/react';
|
||||
import { isString } from 'lodash';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
import { compareFirstLanguages } from '@/utils/tools';
|
||||
import { OauthProvider } from '@/types/user';
|
||||
import { useConfigStore } from '@/stores/config';
|
||||
|
||||
export default function Callback() {
|
||||
const router = useRouter();
|
||||
const setProvider = useSessionStore((s) => s.setProvider);
|
||||
const generateState = useSessionStore((s) => s.generateState);
|
||||
const { data: platformEnv } = useQuery(['getPlatformEnv'], () =>
|
||||
request<any, ApiResp<SystemEnv>>('/api/platform/getEnv')
|
||||
const { data: res } = useQuery(['getPlatformEnv'], () =>
|
||||
request<any, ApiResp<AuthConfigType>>('/api/platform/getLoginConfig')
|
||||
);
|
||||
const { callback_url = '' } = platformEnv?.data ?? {};
|
||||
const conf = res?.data;
|
||||
const callback_url = conf?.callbackURL;
|
||||
const oauthLogin = async ({ url, provider }: { url: string; provider?: OauthProvider }) => {
|
||||
setProvider(provider);
|
||||
window.location.href = url;
|
||||
@@ -80,8 +82,7 @@ export async function getServerSideProps({ req, res, locales }: any) {
|
||||
const local =
|
||||
req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh');
|
||||
res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`);
|
||||
|
||||
const sealos_cloud_domain = process.env.SEALOS_CLOUD_DOMAIN || 'cloud.sealos.io';
|
||||
const sealos_cloud_domain = useConfigStore.getState().cloudConfig?.domain;
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(local, undefined, null, locales || [])),
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useEffect } from 'react';
|
||||
export default function SigninPage() {
|
||||
useEffect(() => {
|
||||
const url = sessionStorage.getItem('accessTemplatesNoLogin');
|
||||
if (url) {
|
||||
if (!!url) {
|
||||
sessionStorage.clear();
|
||||
window.location.replace(url);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ import { IncomingHttpHeaders } from 'http';
|
||||
import { sign, verify } from 'jsonwebtoken';
|
||||
import { JWTPayload } from '@/types';
|
||||
import { AuthenticationTokenPayload, AccessTokenPayload } from '@/types/token';
|
||||
import { getRegionUid } from '@/services/enable';
|
||||
|
||||
const jwtSecret = (process.env.JWT_SECRET as string) || '123456789';
|
||||
const regionJwtSecret = process.env.JWT_SECRET_REGION || '123456789';
|
||||
const appJwtSecret = process.env.JWT_SECRET_APP || '123456789';
|
||||
const regionUID = global.AppConfig?.cloud.regionUID || '123456789';
|
||||
const grobalJwtSecret = global.AppConfig?.desktop.auth.jwt.global || '123456789';
|
||||
const regionalJwtSecret = global.AppConfig?.desktop.auth.jwt.regional || '123456789';
|
||||
const internalJwtSecret = global.AppConfig?.desktop.auth.jwt.internal || '123456789';
|
||||
|
||||
const verifyToken = async <T extends Object>(header: IncomingHttpHeaders) => {
|
||||
try {
|
||||
if (!header?.authorization) {
|
||||
@@ -23,7 +24,7 @@ const verifyToken = async <T extends Object>(header: IncomingHttpHeaders) => {
|
||||
export const verifyAccessToken = async (header: IncomingHttpHeaders) =>
|
||||
verifyToken<AccessTokenPayload>(header).then(
|
||||
(payload) => {
|
||||
if (payload?.regionUid === getRegionUid()) {
|
||||
if (payload?.regionUid === regionUID) {
|
||||
return payload;
|
||||
} else {
|
||||
return null;
|
||||
@@ -37,7 +38,7 @@ export const verifyAuthenticationToken = async (header: IncomingHttpHeaders) =>
|
||||
throw new Error('缺少凭证');
|
||||
}
|
||||
const token = decodeURIComponent(header.authorization);
|
||||
const payload = await verifyJWT<AuthenticationTokenPayload>(token, regionJwtSecret);
|
||||
const payload = await verifyJWT<AuthenticationTokenPayload>(token, grobalJwtSecret);
|
||||
return payload;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@@ -47,7 +48,7 @@ export const verifyAuthenticationToken = async (header: IncomingHttpHeaders) =>
|
||||
export const verifyJWT = <T extends Object = JWTPayload>(token?: string, secret?: string) =>
|
||||
new Promise<T | null>((resolve) => {
|
||||
if (!token) return resolve(null);
|
||||
verify(token, secret || jwtSecret, (err, payload) => {
|
||||
verify(token, secret || regionalJwtSecret, (err, payload) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
resolve(null);
|
||||
@@ -60,8 +61,8 @@ export const verifyJWT = <T extends Object = JWTPayload>(token?: string, secret?
|
||||
});
|
||||
});
|
||||
export const generateAccessToken = (props: AccessTokenPayload) =>
|
||||
sign(props, jwtSecret, { expiresIn: '7d' });
|
||||
sign(props, regionalJwtSecret, { expiresIn: '7d' });
|
||||
export const generateAppToken = (props: AccessTokenPayload) =>
|
||||
sign(props, appJwtSecret, { expiresIn: '7d' });
|
||||
sign(props, internalJwtSecret, { expiresIn: '7d' });
|
||||
export const generateAuthenticationToken = (props: AuthenticationTokenPayload) =>
|
||||
sign(props, regionJwtSecret, { expiresIn: '60000' });
|
||||
sign(props, grobalJwtSecret, { expiresIn: '60000' });
|
||||
|
||||
@@ -4,7 +4,7 @@ export async function connectToDatabase() {
|
||||
if (global.mongodb) {
|
||||
return global.mongodb;
|
||||
}
|
||||
const uri = process.env.MONGODB_URI || '';
|
||||
const uri = global.AppConfig?.database.mongodbURI || '';
|
||||
global.mongodb = new MongoClient(uri);
|
||||
// global.mongodb = 'connecting';
|
||||
try {
|
||||
|
||||
@@ -45,8 +45,8 @@ export async function verifyWechatCode({ code }: { code: string }) {
|
||||
}
|
||||
|
||||
export async function hasWeChatAppSecret() {
|
||||
const APP_ID = process.env.PBULIC_WECHAT_APP_ID;
|
||||
const APP_SECRET = process.env.PBULIC_WECHAT_APP_SECRET;
|
||||
const APP_ID = global.AppConfig?.desktop.auth?.idp.wechat?.clientID;
|
||||
const APP_SECRET = global.AppConfig?.desktop.auth?.idp.wechat?.clientSecret;
|
||||
if (!APP_ID || !APP_SECRET) {
|
||||
throw new Error('Missing WeChat public account key');
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { globalPrisma, prisma } from '@/services/backend/db/init';
|
||||
import { ProviderType, User } from 'prisma/global/generated/client';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { generateAuthenticationToken } from '@/services/backend/auth';
|
||||
import { AuthConfigType } from '@/types';
|
||||
|
||||
async function signIn({ provider, id }: { provider: ProviderType; id: string }) {
|
||||
const userProvider = await globalPrisma.oauthProvider.findUnique({
|
||||
@@ -32,11 +33,12 @@ export const inviteHandler = ({
|
||||
inviterId: string;
|
||||
signResult: any;
|
||||
}) => {
|
||||
const secretKey = process.env.LAF_SECRET_KEY;
|
||||
const baseUrl = process.env.LAF_BASE_URL;
|
||||
const inviteEnabled = process.env.INVITE_ENABLED;
|
||||
const conf = global.AppConfig?.desktop.auth as AuthConfigType;
|
||||
const inviteEnabled = conf.invite?.enabled || false;
|
||||
const secretKey = conf.invite?.lafSecretKey || '';
|
||||
const baseUrl = conf.invite?.lafBaseURL || '';
|
||||
|
||||
if (inviteEnabled !== 'true' || !baseUrl || inviterId === inviteeId) return;
|
||||
if (inviteEnabled || !baseUrl || inviterId === inviteeId) return;
|
||||
|
||||
const payload = {
|
||||
inviterId,
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as Minio from 'minio';
|
||||
import sharp from 'sharp';
|
||||
import { enablePersistImage } from '@/services/enable';
|
||||
|
||||
// todo change env to configs
|
||||
const endPoint = process.env.OS_URL!;
|
||||
const bucketName = process.env.OS_BUCKET_NAME!;
|
||||
const port = Number(process.env.OS_PORT)!;
|
||||
|
||||
@@ -1,47 +1,22 @@
|
||||
// for service
|
||||
import process from 'process';
|
||||
import { AppConfigType } from '@/types';
|
||||
|
||||
export const enablePassword = () =>
|
||||
process.env.PASSWORD_ENABLED === 'true' && !!process.env.PASSWORD_SALT;
|
||||
export const enableGithub = () =>
|
||||
process.env.GITHUB_ENABLED === 'true' &&
|
||||
!!process.env.GITHUB_CLIENT_ID &&
|
||||
!!process.env.GITHUB_CLIENT_SECRET;
|
||||
export const enableSms = () =>
|
||||
process.env.SMS_ENABLED === 'true' &&
|
||||
!!process.env.ALI_ACCESS_KEY_ID &&
|
||||
!!process.env.ALI_ACCESS_KEY_SECRET &&
|
||||
!!process.env.ALI_SIGN_NAME &&
|
||||
!!process.env.ALI_TEMPLATE_CODE;
|
||||
export const enableWechat = () =>
|
||||
process.env.WECHAT_ENABLED === 'true' &&
|
||||
!!process.env.WECHAT_CLIENT_ID &&
|
||||
!!process.env.WECHAT_CLIENT_SECRET;
|
||||
export const enableGoogle = () =>
|
||||
process.env.GOOGLE_ENABLED === 'true' &&
|
||||
!!process.env.GOOGLE_CLIENT_ID &&
|
||||
!!process.env.GOOGLE_CLIENT_SECRET;
|
||||
export const enableRecharge = () => {
|
||||
return process.env.RECHARGE_ENABLED === 'true';
|
||||
};
|
||||
export const enableOpenWechat = () =>
|
||||
!!process.env.PBULIC_WECHAT_APP_ID && !!process.env.PBULIC_WECHAT_APP_SECRET;
|
||||
export const enableSignUp = () => process.env.SIGN_UP_ENABLED === 'true';
|
||||
export const enableApi = () => process.env.API_ENABLED === 'true';
|
||||
// costcenter
|
||||
export const enableStripe = () =>
|
||||
process.env['STRIPE_ENABLED'] === 'true' && !!process.env['STRIPE_PUB'];
|
||||
export const enableWechatRecharge = () => process.env['WECHAT_ENABLED'] === 'true';
|
||||
// license
|
||||
export const enableLicense = () => {
|
||||
return process.env.LICENSE_ENABLED === 'true';
|
||||
};
|
||||
const config = global.AppConfig as AppConfigType;
|
||||
|
||||
export const getTeamLimit = () => parseInt(process.env['TEAM_LIMIT'] || '') || 50;
|
||||
export const enablePassword = () => config.desktop.auth.idp.password?.enabled || false;
|
||||
export const enableGithub = () => config.desktop.auth.idp.github?.enabled || false;
|
||||
export const enableSms = () => config.desktop.auth.idp.sms?.ali?.enabled || false;
|
||||
export const enableWechat = () => config.desktop.auth.idp.wechat?.enabled || false;
|
||||
export const enableGoogle = () => config.desktop.auth.idp.google?.enabled || false;
|
||||
export const enableSignUp = () => config.desktop.auth.signUpEnabled || false;
|
||||
export const enableApi = () => config.common.apiEnabled || false;
|
||||
export const enableOAuth2 = () => config.desktop.auth.idp.oauth2?.enabled || false;
|
||||
|
||||
export const getTeamInviteLimit = () => parseInt(process.env['TEAM_INVITE_LIMIT'] || '') || 50;
|
||||
export const getTeamLimit = () => config.desktop.teamManagement?.maxTeamCount || 50;
|
||||
export const getTeamInviteLimit = () => config.desktop.teamManagement?.maxTeamMemberCount || 50;
|
||||
|
||||
export const getRegionUid = () => process.env['REGION_UID'] || '';
|
||||
export const getRegionUid = () => config.cloud.regionUID;
|
||||
|
||||
export const enablePersistImage = () =>
|
||||
!!process.env.OS_URL &&
|
||||
@@ -50,10 +25,3 @@ export const enablePersistImage = () =>
|
||||
!!process.env.OS_ACCESS_KEY &&
|
||||
!!process.env.OS_SECRET_KEY &&
|
||||
process.env.PERSIST_AVATAR_ENABLED === 'true';
|
||||
|
||||
export const enableOAuth2 = () =>
|
||||
!!process.env.OAUTH2_CLIENT_ID &&
|
||||
!!process.env.OAUTH2_CLIENT_SECRET &&
|
||||
!!process.env.OAUTH2_AUTH_URL &&
|
||||
!!process.env.OAUTH2_TOKEN_URL &&
|
||||
!!process.env.OAUTH2_USERINFO_URL;
|
||||
|
||||
@@ -1,30 +1,39 @@
|
||||
import { getSystemConfig } from '@/api/platform';
|
||||
import { SystemConfigType } from '@/types';
|
||||
import {
|
||||
CloudConfigType,
|
||||
LayoutConfigType,
|
||||
AuthClientConfigType,
|
||||
CommonClientConfigType
|
||||
} from '@/types';
|
||||
import { create } from 'zustand';
|
||||
import { devtools } from 'zustand/middleware';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
export let BackgroundImageUrl = '/images/bg-blue.svg';
|
||||
export let ImageFallBackUrl = '/logo.svg';
|
||||
import { getAppConfig } from '@/api/platform';
|
||||
|
||||
type State = {
|
||||
systemConfig: SystemConfigType | undefined;
|
||||
initSystemConfig: () => Promise<SystemConfigType>;
|
||||
cloudConfig?: CloudConfigType;
|
||||
authConfig?: AuthClientConfigType;
|
||||
commonConfig?: CommonClientConfigType;
|
||||
layoutConfig?: LayoutConfigType;
|
||||
initAppConfig: () => Promise<void>;
|
||||
};
|
||||
|
||||
export const useSystemConfigStore = create<State>()(
|
||||
export const useConfigStore = create<State>()(
|
||||
devtools(
|
||||
immer((set, get) => ({
|
||||
systemConfig: undefined,
|
||||
async initSystemConfig() {
|
||||
const data = await getSystemConfig();
|
||||
BackgroundImageUrl = data.data?.backgroundImageUrl;
|
||||
ImageFallBackUrl = data.data?.imageFallBackUrl;
|
||||
cloudConfig: undefined,
|
||||
authConfig: undefined,
|
||||
commonConfig: undefined,
|
||||
layoutConfig: undefined,
|
||||
|
||||
async initAppConfig() {
|
||||
const data = await getAppConfig();
|
||||
console.log('initAppConfig', data.data);
|
||||
set((state) => {
|
||||
state.systemConfig = data.data;
|
||||
state.layoutConfig = data.data.desktop.layout;
|
||||
state.authConfig = data.data.desktop.auth;
|
||||
state.cloudConfig = data.data.cloud;
|
||||
state.commonConfig = data.data.common;
|
||||
});
|
||||
return data.data;
|
||||
}
|
||||
}))
|
||||
)
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { getSystemEnv } from '@/api/platform';
|
||||
import { SystemEnv } from '@/types';
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
type GlobalState = {
|
||||
systemEnv: SystemEnv;
|
||||
initSystemEnv: () => void;
|
||||
};
|
||||
|
||||
export const useGlobalStore = create<GlobalState>()(
|
||||
immer((set, get) => ({
|
||||
systemEnv: {
|
||||
callback_url: '',
|
||||
cf_sitekey: '',
|
||||
service_protocol_en: '',
|
||||
service_protocol_zh: '',
|
||||
private_protocol_en: '',
|
||||
private_protocol_zh: '',
|
||||
github_client_id: '',
|
||||
google_client_id: '',
|
||||
wechat_client_id: '',
|
||||
licenseEnabled: false,
|
||||
needGithub: false,
|
||||
needGoogle: false,
|
||||
needPassword: false,
|
||||
needSms: false,
|
||||
needWechat: false,
|
||||
private_protocol: '',
|
||||
service_protocol: '',
|
||||
stripeEnabled: false,
|
||||
oauth_proxy: '',
|
||||
guideEnabled: false,
|
||||
wechatEnabledRecharge: false,
|
||||
SEALOS_CLOUD_DOMAIN: 'cloud.sealos.io',
|
||||
rechargeEnabled: false,
|
||||
openWechatEnabled: false,
|
||||
oauth2_client_id: '',
|
||||
oauth2_auth_url: '',
|
||||
needOAuth2: false
|
||||
},
|
||||
async initSystemEnv() {
|
||||
const data = await getSystemEnv();
|
||||
set((state) => {
|
||||
state.systemEnv = data.data;
|
||||
});
|
||||
}
|
||||
}))
|
||||
);
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type MongoClient } from 'mongodb';
|
||||
import { type AppConfigType } from './system';
|
||||
export * from './api';
|
||||
export * from './session';
|
||||
export * from './app';
|
||||
@@ -9,8 +10,10 @@ export * from './login';
|
||||
export * from './valuation';
|
||||
export * from './license';
|
||||
export * from './region';
|
||||
|
||||
declare global {
|
||||
var mongodb: MongoClient | null;
|
||||
var AppConfig: AppConfigType;
|
||||
var WechatAccessToken: string | undefined;
|
||||
var WechatExpiresIn: number | undefined;
|
||||
}
|
||||
|
||||
@@ -1,45 +1,239 @@
|
||||
export type SystemConfigType = {
|
||||
scripts: ScriptConfig[];
|
||||
isSystemConfigEnabled: boolean; // Compatible with older versions
|
||||
backgroundImageUrl: string;
|
||||
imageFallBackUrl: string;
|
||||
title: string;
|
||||
metaTitle: string;
|
||||
metaDescription: string;
|
||||
showGithubStar: boolean;
|
||||
import { DeepRequired, OmitPath, OmitPathArr } from './tools';
|
||||
|
||||
export type CloudConfigType = {
|
||||
domain: string;
|
||||
port: string;
|
||||
regionUID: string;
|
||||
certSecretName: string;
|
||||
};
|
||||
|
||||
export type ScriptConfig = {
|
||||
export type CommonConfigType = {
|
||||
guideEnabled: boolean;
|
||||
apiEnabled: boolean;
|
||||
rechargeEnabled: boolean;
|
||||
cfSiteKey?: string;
|
||||
};
|
||||
export type CommonClientConfigType = DeepRequired<OmitPath<CommonConfigType, 'apiEnabled'>>;
|
||||
export type DatabaseConfigType = {
|
||||
mongodbURI: string;
|
||||
globalCockroachdbURI: string;
|
||||
regionalCockroachdbURI: string;
|
||||
};
|
||||
|
||||
export type MetaConfigType = {
|
||||
title: string;
|
||||
description: string;
|
||||
keywords: string;
|
||||
scripts?: MetaScriptType[];
|
||||
};
|
||||
|
||||
export type MetaScriptType = {
|
||||
src: string;
|
||||
'data-website-id'?: string;
|
||||
};
|
||||
|
||||
export type LoginProps = {
|
||||
wechat_client_id: string;
|
||||
github_client_id: string;
|
||||
google_client_id: string;
|
||||
callback_url: string;
|
||||
cf_sitekey: string;
|
||||
service_protocol_zh: string;
|
||||
private_protocol_zh: string;
|
||||
service_protocol_en: string;
|
||||
private_protocol_en: string;
|
||||
needPassword: boolean;
|
||||
oauth_proxy: string;
|
||||
needSms: boolean;
|
||||
needGithub: boolean;
|
||||
needWechat: boolean;
|
||||
needGoogle: boolean;
|
||||
oauth2_client_id: string;
|
||||
oauth2_auth_url: string;
|
||||
needOAuth2: boolean;
|
||||
export type ProtocolConfigType = {
|
||||
serviceProtocol: {
|
||||
zh: string;
|
||||
en: string;
|
||||
};
|
||||
privateProtocol: {
|
||||
zh: string;
|
||||
en: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type SystemEnv = {
|
||||
SEALOS_CLOUD_DOMAIN: string;
|
||||
wechatEnabledRecharge: boolean;
|
||||
rechargeEnabled: boolean;
|
||||
licenseEnabled: boolean;
|
||||
guideEnabled: boolean;
|
||||
openWechatEnabled: boolean;
|
||||
} & LoginProps;
|
||||
export type LayoutConfigType = {
|
||||
title: string;
|
||||
logo: string;
|
||||
backgroundImage: string;
|
||||
meta: MetaConfigType;
|
||||
|
||||
protocol?: ProtocolConfigType;
|
||||
common: {
|
||||
githubStarEnabled: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type AuthConfigType = {
|
||||
proxyAddress?: string;
|
||||
callbackURL: string;
|
||||
signUpEnabled?: boolean;
|
||||
baiduToken?: string;
|
||||
jwt: JwtConfigType;
|
||||
invite?: {
|
||||
enabled: boolean;
|
||||
lafSecretKey: string;
|
||||
lafBaseURL: string;
|
||||
};
|
||||
idp: {
|
||||
password?: {
|
||||
enabled: boolean;
|
||||
salt?: string;
|
||||
};
|
||||
github?: {
|
||||
enabled: boolean;
|
||||
clientID: string;
|
||||
clientSecret?: string;
|
||||
};
|
||||
wechat?: {
|
||||
enabled: boolean;
|
||||
clientID: string;
|
||||
clientSecret?: string;
|
||||
};
|
||||
google?: {
|
||||
enabled: boolean;
|
||||
clientID: string;
|
||||
clientSecret?: string;
|
||||
};
|
||||
sms?: {
|
||||
enabled: boolean;
|
||||
ali?: {
|
||||
enabled: boolean;
|
||||
endpoint: string;
|
||||
templateCode: string;
|
||||
signName: string;
|
||||
accessKeyID: string;
|
||||
accessKeySecret?: string;
|
||||
};
|
||||
};
|
||||
oauth2?: {
|
||||
enabled: boolean;
|
||||
callbackURL: string;
|
||||
clientID: string;
|
||||
clientSecret?: string;
|
||||
authURL: string;
|
||||
tokenURL: string;
|
||||
userInfoURL: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type AuthClientConfigType = DeepRequired<
|
||||
OmitPathArr<
|
||||
AuthConfigType,
|
||||
[
|
||||
'signUpEnabled',
|
||||
'invite.lafSecretKey',
|
||||
'invite.lafBaseURL',
|
||||
'idp.password.salt',
|
||||
'idp.github.clientSecret',
|
||||
'idp.wechat.clientSecret',
|
||||
'idp.google.clientSecret',
|
||||
'idp.sms.ali',
|
||||
'idp.oauth2.clientSecret',
|
||||
'jwt'
|
||||
]
|
||||
>
|
||||
>;
|
||||
|
||||
export type JwtConfigType = {
|
||||
internal?: string;
|
||||
regional?: string;
|
||||
global?: string;
|
||||
};
|
||||
|
||||
export type DesktopConfigType<T = AuthConfigType> = {
|
||||
layout: LayoutConfigType;
|
||||
auth: T;
|
||||
teamManagement?: {
|
||||
maxTeamCount: number;
|
||||
maxTeamMemberCount: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type AppConfigType = {
|
||||
cloud: CloudConfigType;
|
||||
common: CommonConfigType;
|
||||
database: DatabaseConfigType;
|
||||
desktop: DesktopConfigType;
|
||||
};
|
||||
export type AppClientConfigType = {
|
||||
cloud: CloudConfigType;
|
||||
common: CommonClientConfigType;
|
||||
desktop: DesktopConfigType<AuthClientConfigType>;
|
||||
};
|
||||
|
||||
export const DefaultCommonClientConfig: CommonClientConfigType = {
|
||||
guideEnabled: false,
|
||||
rechargeEnabled: false,
|
||||
cfSiteKey: ''
|
||||
};
|
||||
|
||||
export const DefaultCloudConfig: CloudConfigType = {
|
||||
domain: 'cloud.sealos.io',
|
||||
port: '443',
|
||||
regionUID: 'sealos-cloud',
|
||||
certSecretName: 'wildcard-cert'
|
||||
};
|
||||
|
||||
export const DefaultLayoutConfig: LayoutConfigType = {
|
||||
title: 'Sealos Cloud',
|
||||
logo: '/logo.svg',
|
||||
backgroundImage: '/images/bg-blue.svg',
|
||||
protocol: {
|
||||
serviceProtocol: {
|
||||
zh: '',
|
||||
en: ''
|
||||
},
|
||||
privateProtocol: {
|
||||
zh: '',
|
||||
en: ''
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
title: 'Sealos Cloud',
|
||||
description: 'Sealos Cloud',
|
||||
keywords: 'Sealos Cloud',
|
||||
scripts: []
|
||||
},
|
||||
common: {
|
||||
githubStarEnabled: false
|
||||
}
|
||||
};
|
||||
|
||||
export const DefaultAuthClientConfig: AuthClientConfigType = {
|
||||
baiduToken: '',
|
||||
invite: {
|
||||
enabled: false
|
||||
},
|
||||
callbackURL: 'https://cloud.sealos.io/callback',
|
||||
idp: {
|
||||
password: {
|
||||
enabled: true
|
||||
},
|
||||
github: {
|
||||
enabled: false,
|
||||
clientID: ''
|
||||
},
|
||||
wechat: {
|
||||
enabled: false,
|
||||
clientID: ''
|
||||
},
|
||||
google: {
|
||||
enabled: false,
|
||||
clientID: ''
|
||||
},
|
||||
sms: {
|
||||
enabled: false
|
||||
},
|
||||
oauth2: {
|
||||
enabled: false,
|
||||
callbackURL: '',
|
||||
clientID: '',
|
||||
authURL: '',
|
||||
tokenURL: '',
|
||||
userInfoURL: ''
|
||||
}
|
||||
},
|
||||
proxyAddress: ''
|
||||
};
|
||||
|
||||
export const DefaultAppClientConfig: AppClientConfigType = {
|
||||
cloud: DefaultCloudConfig,
|
||||
common: DefaultCommonClientConfig,
|
||||
desktop: {
|
||||
layout: DefaultLayoutConfig,
|
||||
auth: DefaultAuthClientConfig
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
export type Primitive = undefined | null | boolean | string | number | symbol | bigint | Function;
|
||||
|
||||
export type DeepRequired<T> = T extends Primitive
|
||||
? NonNullable<T>
|
||||
: {
|
||||
[P in keyof T]-?: T[P] extends Array<infer U>
|
||||
? Array<DeepRequired<U>>
|
||||
: T[P] extends ReadonlyArray<infer V>
|
||||
? DeepRequired<V>
|
||||
: DeepRequired<T[P]>;
|
||||
};
|
||||
export type Replace<Obj, k extends keyof Obj, v> = k extends keyof Obj
|
||||
? { [p in keyof Obj]: p extends k ? v : Obj[p] }
|
||||
: never;
|
||||
|
||||
export type OmitPath<
|
||||
Obj extends unknown,
|
||||
Path extends string
|
||||
> = Path extends `${infer p}.${infer Rest}`
|
||||
? p extends keyof Obj
|
||||
? Replace<Obj, p, OmitPath<NonNullable<Obj[p]>, Rest>>
|
||||
: Obj
|
||||
: Path extends keyof Obj
|
||||
? { [P in Exclude<keyof Obj, Path>]: Obj[P] }
|
||||
: Obj;
|
||||
|
||||
export type OmitPathArr<Obj, Paths extends unknown[]> = Paths extends [infer Head, ...infer Rest]
|
||||
? Head extends string
|
||||
? OmitPathArr<OmitPath<Obj, Head>, Rest>
|
||||
: never
|
||||
: Obj;
|
||||
@@ -3,7 +3,7 @@ import * as crypto from 'crypto';
|
||||
// use sha256 to hash the password
|
||||
export function hashPassword(password: string): string {
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(password + process.env.PASSWORD_SALT);
|
||||
hash.update(password + global.AppConfig?.desktop.auth.idp.password?.salt || '');
|
||||
return hash.digest('hex');
|
||||
}
|
||||
|
||||
|
||||
@@ -9,4 +9,4 @@ module.exports = {
|
||||
locales: ['en', 'zh'],
|
||||
localeDetection: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||
const { i18n } = require('./next-i18next.config')
|
||||
const analyzer = process.env === 'production' ? [new BundleAnalyzerPlugin()] : []
|
||||
const path = require('path')
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const { i18n } = require('./next-i18next.config');
|
||||
const analyzer = process.env === 'production' ? [new BundleAnalyzerPlugin()] : [];
|
||||
const path = require('path');
|
||||
|
||||
const nextConfig = {
|
||||
i18n,
|
||||
@@ -16,15 +16,15 @@ const nextConfig = {
|
||||
issuer: /\.[jt]sx?$/,
|
||||
use: ['@svgr/webpack']
|
||||
}
|
||||
])
|
||||
config.plugins = [...config.plugins, ...analyzer]
|
||||
return config
|
||||
]);
|
||||
config.plugins = [...config.plugins, ...analyzer];
|
||||
return config;
|
||||
},
|
||||
transpilePackages: ['@sealos/ui', 'sealos-desktop-sdk', '@sealos/driver'],
|
||||
experimental: {
|
||||
// this includes files from the monorepo base two directories up
|
||||
outputFileTracingRoot: path.join(__dirname, '../../')
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = nextConfig
|
||||
module.exports = nextConfig;
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"include": ["next-env.d.ts", "src/**/*.ts", "src/**/*.tsx"],
|
||||
"extends": "../../tsconfig.web.json"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user