feat: integrate tuwunel with Ory SSO, rename chat to messages subdomain
- Add matrix to hydra-maester enabledNamespaces for OAuth2Client CRD - Update allowed_return_urls and selfservice URLs: chat→messages - Add Kratos verification flow, employee/external identity schemas - Extend session lifespan to 30 days with persistent cookies - Route messages.* to tuwunel via Pingora with WebSocket support - Replace login-ui with kratos-admin-ui as unified auth frontend - Update TLS certificate SANs: chat→messages, add monitoring subdomains - Add tuwunel + La Suite images to production overlay - Switch DDoS/scanner detection to compiled-in ensemble models (observe_only)
This commit is contained in:
@@ -21,7 +21,7 @@ data:
|
||||
key_path = "/etc/tls/tls.key"
|
||||
|
||||
[telemetry]
|
||||
otlp_endpoint = "http://tempo.monitoring.svc.cluster.local:4318"
|
||||
otlp_endpoint = ""
|
||||
metrics_port = 9090
|
||||
|
||||
# Kubernetes resource names for cert/config watchers.
|
||||
@@ -31,22 +31,20 @@ data:
|
||||
tls_secret = "pingora-tls"
|
||||
config_configmap = "pingora-config"
|
||||
|
||||
# DDoS detection — KNN-based per-IP behavioral classification.
|
||||
# DDoS detection — decision tree + MLP ensemble (compiled-in weights).
|
||||
[ddos]
|
||||
enabled = true
|
||||
model_path = "/models/ddos_model.bin"
|
||||
k = 5
|
||||
observe_only = true
|
||||
threshold = 0.6
|
||||
window_secs = 60
|
||||
window_capacity = 1000
|
||||
min_events = 10
|
||||
|
||||
# Scanner detection — logistic regression per-request classification.
|
||||
# Scanner detection — decision tree + MLP ensemble (compiled-in weights).
|
||||
[scanner]
|
||||
enabled = true
|
||||
model_path = "/models/scanner_model.bin"
|
||||
observe_only = true
|
||||
threshold = 0.5
|
||||
poll_interval_secs = 30
|
||||
bot_cache_ttl_secs = 86400
|
||||
|
||||
[[scanner.allowlist]]
|
||||
@@ -61,6 +59,10 @@ data:
|
||||
dns_suffixes = ["search.msn.com"]
|
||||
cidrs = ["40.77.167.0/24", "157.55.39.0/24"]
|
||||
|
||||
[[scanner.allowlist]]
|
||||
ua_prefix = "containerd"
|
||||
reason = "Container registry client (buildkitd/containerd)"
|
||||
|
||||
# Rate limiting — leaky bucket per-identity throttling.
|
||||
[rate_limit]
|
||||
enabled = true
|
||||
@@ -146,7 +148,7 @@ data:
|
||||
backend = "http://messages-frontend.lasuite.svc.cluster.local:80"
|
||||
|
||||
[[routes]]
|
||||
host_prefix = "chat"
|
||||
host_prefix = "messages"
|
||||
backend = "http://tuwunel.matrix.svc.cluster.local:6167"
|
||||
websocket = true
|
||||
|
||||
@@ -181,10 +183,10 @@ data:
|
||||
backend = "http://gitea-http.devtools.svc.cluster.local:3000"
|
||||
websocket = true
|
||||
|
||||
# auth: login-ui handles browser UI; Hydra handles OAuth2/OIDC; Kratos handles self-service flows.
|
||||
# auth: unified IAM dashboard; Hydra handles OAuth2/OIDC; Kratos handles self-service flows.
|
||||
[[routes]]
|
||||
host_prefix = "auth"
|
||||
backend = "http://login-ui.ory.svc.cluster.local:3000"
|
||||
backend = "http://kratos-admin-ui.ory.svc.cluster.local:3000"
|
||||
|
||||
[[routes.paths]]
|
||||
prefix = "/oauth2"
|
||||
@@ -204,10 +206,6 @@ data:
|
||||
backend = "http://kratos-public.ory.svc.cluster.local:80"
|
||||
strip_prefix = true
|
||||
|
||||
[[routes]]
|
||||
host_prefix = "admin"
|
||||
backend = "http://kratos-admin-ui.ory.svc.cluster.local:3000"
|
||||
|
||||
[[routes]]
|
||||
host_prefix = "integration"
|
||||
backend = "http://integration.lasuite.svc.cluster.local:80"
|
||||
|
||||
@@ -16,9 +16,12 @@ hydra:
|
||||
error: https://auth.DOMAIN_SUFFIX/error
|
||||
|
||||
ttl:
|
||||
# Short access tokens — API-level auth window is tight.
|
||||
access_token: 5m
|
||||
id_token: 5m
|
||||
# Login session persists 30 days — matches Kratos session lifespan so the
|
||||
# Hydra session cookie survives browser restarts and prompt=none keeps working.
|
||||
authentication_session: 720h
|
||||
# Access/ID tokens renewed via refresh token; 1h keeps the window short.
|
||||
access_token: 1h
|
||||
id_token: 1h
|
||||
# Refresh tokens last 30 days; Kratos session carries silent re-auth.
|
||||
# Revoking a Kratos session (sunbeam user disable) prevents refresh.
|
||||
refresh_token: 720h
|
||||
@@ -42,6 +45,7 @@ secret:
|
||||
hydra-maester:
|
||||
enabledNamespaces:
|
||||
- lasuite
|
||||
- matrix
|
||||
|
||||
deployment:
|
||||
extraEnv:
|
||||
|
||||
@@ -25,12 +25,18 @@ spec:
|
||||
value: "http://kratos-public.ory.svc.cluster.local:80"
|
||||
- name: KRATOS_ADMIN_URL
|
||||
value: "http://kratos-admin.ory.svc.cluster.local:80"
|
||||
- name: HYDRA_ADMIN_URL
|
||||
value: "http://hydra-admin.ory.svc.cluster.local:4445"
|
||||
- name: PUBLIC_URL
|
||||
value: "https://admin.DOMAIN_SUFFIX"
|
||||
value: "https://auth.DOMAIN_SUFFIX"
|
||||
- name: CUNNINGHAM_THEME
|
||||
value: "dsfr-light"
|
||||
- name: PORT
|
||||
value: "3000"
|
||||
- name: TRUSTED_CLIENT_IDS
|
||||
value: ""
|
||||
- name: SEAWEEDFS_S3_URL
|
||||
value: "http://seaweedfs-filer.storage.svc.cluster.local:8333"
|
||||
- name: ADMIN_IDENTITY_IDS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
@@ -46,9 +52,19 @@ spec:
|
||||
secretKeyRef:
|
||||
name: kratos-admin-ui-secrets
|
||||
key: csrf-cookie-secret
|
||||
- name: SEAWEEDFS_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: kratos-admin-ui-secrets
|
||||
key: s3-access-key
|
||||
- name: SEAWEEDFS_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: kratos-admin-ui-secrets
|
||||
key: s3-secret-key
|
||||
resources:
|
||||
limits:
|
||||
memory: 256Mi
|
||||
memory: 384Mi
|
||||
requests:
|
||||
memory: 64Mi
|
||||
cpu: 25m
|
||||
|
||||
@@ -17,7 +17,7 @@ data:
|
||||
- https://meet.DOMAIN_SUFFIX/
|
||||
- https://drive.DOMAIN_SUFFIX/
|
||||
- https://mail.DOMAIN_SUFFIX/
|
||||
- https://chat.DOMAIN_SUFFIX/
|
||||
- https://messages.DOMAIN_SUFFIX/
|
||||
- https://people.DOMAIN_SUFFIX/
|
||||
- https://src.DOMAIN_SUFFIX/
|
||||
- https://admin.DOMAIN_SUFFIX/
|
||||
|
||||
@@ -16,7 +16,7 @@ kratos:
|
||||
- https://meet.DOMAIN_SUFFIX/
|
||||
- https://drive.DOMAIN_SUFFIX/
|
||||
- https://mail.DOMAIN_SUFFIX/
|
||||
- https://chat.DOMAIN_SUFFIX/
|
||||
- https://messages.DOMAIN_SUFFIX/
|
||||
- https://people.DOMAIN_SUFFIX/
|
||||
- https://src.DOMAIN_SUFFIX/
|
||||
- https://find.DOMAIN_SUFFIX/
|
||||
@@ -32,14 +32,19 @@ kratos:
|
||||
recovery:
|
||||
enabled: true
|
||||
ui_url: https://auth.DOMAIN_SUFFIX/recovery
|
||||
verification:
|
||||
enabled: true
|
||||
ui_url: https://auth.DOMAIN_SUFFIX/verification
|
||||
settings:
|
||||
ui_url: https://auth.DOMAIN_SUFFIX/settings
|
||||
|
||||
identity:
|
||||
default_schema_id: default
|
||||
default_schema_id: employee
|
||||
schemas:
|
||||
- id: default
|
||||
url: base64://ewogICIkaWQiOiAiaHR0cHM6Ly9zY2hlbWFzLnN1bmJlYW0uc3R1ZGlvL2lkZW50aXR5Lmpzb24iLAogICIkc2NoZW1hIjogImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDcvc2NoZW1hIyIsCiAgInR5cGUiOiAib2JqZWN0IiwKICAidGl0bGUiOiAiUGVyc29uIiwKICAicHJvcGVydGllcyI6IHsKICAgICJ0cmFpdHMiOiB7CiAgICAgICJ0eXBlIjogIm9iamVjdCIsCiAgICAgICJwcm9wZXJ0aWVzIjogewogICAgICAgICJlbWFpbCI6IHsKICAgICAgICAgICJ0eXBlIjogInN0cmluZyIsCiAgICAgICAgICAiZm9ybWF0IjogImVtYWlsIiwKICAgICAgICAgICJ0aXRsZSI6ICJFbWFpbCIsCiAgICAgICAgICAib3J5LnNoL2tyYXRvcyI6IHsKICAgICAgICAgICAgImNyZWRlbnRpYWxzIjogewogICAgICAgICAgICAgICJwYXNzd29yZCI6IHsKICAgICAgICAgICAgICAgICJpZGVudGlmaWVyIjogdHJ1ZQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgInJlY292ZXJ5IjogewogICAgICAgICAgICAgICJ2aWEiOiAiZW1haWwiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJ2ZXJpZmljYXRpb24iOiB7CiAgICAgICAgICAgICAgInZpYSI6ICJlbWFpbCIKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgIm5hbWUiOiB7CiAgICAgICAgICAidHlwZSI6ICJvYmplY3QiLAogICAgICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgICAgICJmaXJzdCI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIkZpcnN0IG5hbWUiIH0sCiAgICAgICAgICAgICJsYXN0IjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiTGFzdCBuYW1lIiB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9LAogICAgICAicmVxdWlyZWQiOiBbImVtYWlsIl0KICAgIH0KICB9Cn0K
|
||||
- id: employee
|
||||
url: base64://ewogICIkaWQiOiAiaHR0cHM6Ly9zY2hlbWFzLnN1bmJlYW0uc3R1ZGlvL2VtcGxveWVlLmpzb24iLAogICIkc2NoZW1hIjogImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDcvc2NoZW1hIyIsCiAgInR5cGUiOiAib2JqZWN0IiwKICAidGl0bGUiOiAiRW1wbG95ZWUiLAogICJwcm9wZXJ0aWVzIjogewogICAgInRyYWl0cyI6IHsKICAgICAgInR5cGUiOiAib2JqZWN0IiwKICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgImVtYWlsIjogewogICAgICAgICAgInR5cGUiOiAic3RyaW5nIiwKICAgICAgICAgICJmb3JtYXQiOiAiZW1haWwiLAogICAgICAgICAgInRpdGxlIjogIkVtYWlsIiwKICAgICAgICAgICJvcnkuc2gva3JhdG9zIjogewogICAgICAgICAgICAiY3JlZGVudGlhbHMiOiB7ICJwYXNzd29yZCI6IHsgImlkZW50aWZpZXIiOiB0cnVlIH0gfSwKICAgICAgICAgICAgInJlY292ZXJ5IjogeyAidmlhIjogImVtYWlsIiB9LAogICAgICAgICAgICAidmVyaWZpY2F0aW9uIjogeyAidmlhIjogImVtYWlsIiB9CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAiZ2l2ZW5fbmFtZSI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIkZpcnN0IG5hbWUiIH0sCiAgICAgICAgImZhbWlseV9uYW1lIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiTGFzdCBuYW1lIiB9LAogICAgICAgICJtaWRkbGVfbmFtZSI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIk1pZGRsZSBuYW1lIiB9LAogICAgICAgICJuaWNrbmFtZSI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIk5pY2tuYW1lIiB9LAogICAgICAgICJwaWN0dXJlIjogeyAidHlwZSI6ICJzdHJpbmciLCAiZm9ybWF0IjogInVyaSIsICJ0aXRsZSI6ICJQcm9maWxlIHBpY3R1cmUiIH0sCiAgICAgICAgInBob25lX251bWJlciI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIlBob25lIG51bWJlciIgfSwKICAgICAgICAiam9iX3RpdGxlIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiSm9iIHRpdGxlIiB9LAogICAgICAgICJkZXBhcnRtZW50IjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiRGVwYXJ0bWVudCIgfSwKICAgICAgICAib2ZmaWNlX2xvY2F0aW9uIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiT2ZmaWNlIGxvY2F0aW9uIiB9LAogICAgICAgICJlbXBsb3llZV9pZCI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIkVtcGxveWVlIElEIiB9LAogICAgICAgICJoaXJlX2RhdGUiOiB7ICJ0eXBlIjogInN0cmluZyIsICJmb3JtYXQiOiAiZGF0ZSIsICJ0aXRsZSI6ICJIaXJlIGRhdGUiIH0sCiAgICAgICAgIm1hbmFnZXIiOiB7ICJ0eXBlIjogInN0cmluZyIsICJ0aXRsZSI6ICJNYW5hZ2VyIiB9CiAgICAgIH0sCiAgICAgICJyZXF1aXJlZCI6IFsiZW1haWwiXQogICAgfQogIH0KfQo=
|
||||
- id: external
|
||||
url: base64://ewogICIkaWQiOiAiaHR0cHM6Ly9zY2hlbWFzLnN1bmJlYW0uc3R1ZGlvL2V4dGVybmFsLmpzb24iLAogICIkc2NoZW1hIjogImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDcvc2NoZW1hIyIsCiAgInR5cGUiOiAib2JqZWN0IiwKICAidGl0bGUiOiAiRXh0ZXJuYWwgVXNlciIsCiAgInByb3BlcnRpZXMiOiB7CiAgICAidHJhaXRzIjogewogICAgICAidHlwZSI6ICJvYmplY3QiLAogICAgICAicHJvcGVydGllcyI6IHsKICAgICAgICAiZW1haWwiOiB7CiAgICAgICAgICAidHlwZSI6ICJzdHJpbmciLAogICAgICAgICAgImZvcm1hdCI6ICJlbWFpbCIsCiAgICAgICAgICAidGl0bGUiOiAiRW1haWwiLAogICAgICAgICAgIm9yeS5zaC9rcmF0b3MiOiB7CiAgICAgICAgICAgICJjcmVkZW50aWFscyI6IHsgInBhc3N3b3JkIjogeyAiaWRlbnRpZmllciI6IHRydWUgfSB9LAogICAgICAgICAgICAicmVjb3ZlcnkiOiB7ICJ2aWEiOiAiZW1haWwiIH0sCiAgICAgICAgICAgICJ2ZXJpZmljYXRpb24iOiB7ICJ2aWEiOiAiZW1haWwiIH0KICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgICJnaXZlbl9uYW1lIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiRmlyc3QgbmFtZSIgfSwKICAgICAgICAiZmFtaWx5X25hbWUiOiB7ICJ0eXBlIjogInN0cmluZyIsICJ0aXRsZSI6ICJMYXN0IG5hbWUiIH0sCiAgICAgICAgIm5pY2tuYW1lIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiTmlja25hbWUiIH0sCiAgICAgICAgInBpY3R1cmUiOiB7ICJ0eXBlIjogInN0cmluZyIsICJmb3JtYXQiOiAidXJpIiwgInRpdGxlIjogIlByb2ZpbGUgcGljdHVyZSIgfQogICAgICB9LAogICAgICAicmVxdWlyZWQiOiBbImVtYWlsIl0KICAgIH0KICB9Cn0K
|
||||
|
||||
courier:
|
||||
smtp:
|
||||
@@ -56,6 +61,8 @@ kratos:
|
||||
# receive it. Without this Kratos scopes the cookie to auth.* only, causing
|
||||
# redirect loops on admin.*.
|
||||
domain: DOMAIN_SUFFIX
|
||||
persistent: true
|
||||
lifespan: 720h
|
||||
|
||||
serve:
|
||||
public:
|
||||
|
||||
@@ -9,7 +9,6 @@ kind: Kustomization
|
||||
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- login-ui-deployment.yaml
|
||||
- kratos-admin-deployment.yaml
|
||||
# Hydra chart CRDs are not rendered by helm template; apply manually.
|
||||
- hydra-oauth2client-crd.yaml
|
||||
|
||||
@@ -58,12 +58,15 @@ spec:
|
||||
- meet.DOMAIN_SUFFIX
|
||||
- drive.DOMAIN_SUFFIX
|
||||
- mail.DOMAIN_SUFFIX
|
||||
- chat.DOMAIN_SUFFIX
|
||||
- messages.DOMAIN_SUFFIX
|
||||
- people.DOMAIN_SUFFIX
|
||||
- src.DOMAIN_SUFFIX
|
||||
- auth.DOMAIN_SUFFIX
|
||||
- s3.DOMAIN_SUFFIX
|
||||
- grafana.DOMAIN_SUFFIX
|
||||
- metrics.DOMAIN_SUFFIX
|
||||
- systemmetrics.DOMAIN_SUFFIX
|
||||
- systemlogs.DOMAIN_SUFFIX
|
||||
- systemtracing.DOMAIN_SUFFIX
|
||||
- admin.DOMAIN_SUFFIX
|
||||
- integration.DOMAIN_SUFFIX
|
||||
- livekit.DOMAIN_SUFFIX
|
||||
|
||||
@@ -7,6 +7,7 @@ kind: Kustomization
|
||||
# sunbeam apply --env production --domain yourdomain.com
|
||||
|
||||
resources:
|
||||
- ../../base/build
|
||||
- ../../base/longhorn
|
||||
- ../../base/cert-manager
|
||||
- ../../base/ingress
|
||||
@@ -18,6 +19,7 @@ resources:
|
||||
- ../../base/devtools
|
||||
- ../../base/vso
|
||||
- ../../base/monitoring
|
||||
- ../../base/matrix
|
||||
# cert-manager ClusterIssuer + Certificate (requires cert-manager to be installed)
|
||||
- cert-manager.yaml
|
||||
# CNPG daily backup schedule
|
||||
@@ -37,6 +39,36 @@ images:
|
||||
newName: src.DOMAIN_SUFFIX/studio/meet-frontend
|
||||
newTag: latest
|
||||
|
||||
# people-frontend — built from source with estudio theme baked in.
|
||||
- name: lasuite/people-frontend
|
||||
newName: src.DOMAIN_SUFFIX/studio/people-frontend
|
||||
newTag: latest
|
||||
|
||||
# Messages — built from source and pushed to Gitea registry.
|
||||
- name: messages-backend
|
||||
newName: src.DOMAIN_SUFFIX/studio/messages-backend
|
||||
newTag: latest
|
||||
- name: messages-frontend
|
||||
newName: src.DOMAIN_SUFFIX/studio/messages-frontend
|
||||
newTag: latest
|
||||
- name: messages-mta-in
|
||||
newName: src.DOMAIN_SUFFIX/studio/messages-mta-in
|
||||
newTag: latest
|
||||
- name: messages-mta-out
|
||||
newName: src.DOMAIN_SUFFIX/studio/messages-mta-out
|
||||
newTag: latest
|
||||
- name: messages-mpa
|
||||
newName: src.DOMAIN_SUFFIX/studio/messages-mpa
|
||||
newTag: latest
|
||||
- name: messages-socks-proxy
|
||||
newName: src.DOMAIN_SUFFIX/studio/messages-socks-proxy
|
||||
newTag: latest
|
||||
|
||||
# Tuwunel Matrix homeserver — built and pushed by `sunbeam build tuwunel`
|
||||
- name: tuwunel
|
||||
newName: src.DOMAIN_SUFFIX/studio/tuwunel
|
||||
newTag: latest
|
||||
|
||||
patches:
|
||||
# Pingora host ports — bind :80/:443 to the host network
|
||||
- path: patch-pingora-hostport.yaml
|
||||
@@ -53,5 +85,18 @@ patches:
|
||||
# OpenSearch: expand PVC to 50 Gi
|
||||
- path: patch-opensearch-storage.yaml
|
||||
|
||||
# Tuwunel: production resource limits and PVC sizing
|
||||
- path: patch-tuwunel.yaml
|
||||
|
||||
# SeaweedFS volume: expand PVC to 600 Gi
|
||||
- path: patch-seaweedfs-volume-size.yaml
|
||||
|
||||
# MTA-in: bind port 25 to the host for inbound email delivery
|
||||
- patch: |
|
||||
- op: add
|
||||
path: /spec/template/spec/containers/0/ports/0/hostPort
|
||||
value: 25
|
||||
target:
|
||||
kind: Deployment
|
||||
name: messages-mta-in
|
||||
namespace: lasuite
|
||||
|
||||
@@ -197,7 +197,7 @@ echo " Auth: https://auth.${DOMAIN}/"
|
||||
echo " Docs: https://docs.${DOMAIN}/"
|
||||
echo " Meet: https://meet.${DOMAIN}/"
|
||||
echo " Drive: https://drive.${DOMAIN}/"
|
||||
echo " Chat: https://chat.${DOMAIN}/"
|
||||
echo " Messages: https://messages.${DOMAIN}/"
|
||||
echo " Mail: https://mail.${DOMAIN}/"
|
||||
echo " People: https://people.${DOMAIN}/"
|
||||
echo " Gitea: https://src.${DOMAIN}/"
|
||||
|
||||
@@ -18,7 +18,7 @@ echo " Docs: https://docs.${BASE}"
|
||||
echo " Meet: https://meet.${BASE}"
|
||||
echo " Drive: https://drive.${BASE}"
|
||||
echo " Mail: https://mail.${BASE}"
|
||||
echo " Chat: https://chat.${BASE}"
|
||||
echo " Messages: https://messages.${BASE}"
|
||||
echo " People: https://people.${BASE}"
|
||||
echo " Source: https://src.${BASE}"
|
||||
echo " Auth: https://auth.${BASE}"
|
||||
|
||||
Reference in New Issue
Block a user