Compare commits
22 Commits
remove-ses
...
patch-1
Author | SHA1 | Date | |
---|---|---|---|
c4271b1ff7 | |||
d37f025881 | |||
149815885d | |||
be46545613 | |||
9d3822373a | |||
ab84adc13f | |||
689c59fe1c | |||
b8578623fc | |||
ae4947e85b | |||
5e840baf84 | |||
df5ec2c020 | |||
f4c64b49c2 | |||
1c022cb366 | |||
ebd620562c | |||
7ecdc1e681 | |||
56bb76c4ef | |||
8c2ba9176b | |||
11cbde771b | |||
14b6fc5d85 | |||
5d8630595d | |||
54f4b83cf7 | |||
3b6de494c9 |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 2025.4.1
|
current_version = 2025.4.0
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
||||||
|
12
.github/dependabot.yml
vendored
12
.github/dependabot.yml
vendored
@ -118,15 +118,3 @@ updates:
|
|||||||
prefix: "core:"
|
prefix: "core:"
|
||||||
labels:
|
labels:
|
||||||
- dependencies
|
- dependencies
|
||||||
- package-ecosystem: docker-compose
|
|
||||||
directories:
|
|
||||||
# - /scripts # Maybe
|
|
||||||
- /tests/e2e
|
|
||||||
schedule:
|
|
||||||
interval: daily
|
|
||||||
time: "04:00"
|
|
||||||
open-pull-requests-limit: 10
|
|
||||||
commit-message:
|
|
||||||
prefix: "core:"
|
|
||||||
labels:
|
|
||||||
- dependencies
|
|
||||||
|
3
.github/workflows/ci-main.yml
vendored
3
.github/workflows/ci-main.yml
vendored
@ -200,7 +200,7 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: web/dist
|
path: web/dist
|
||||||
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
|
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**') }}
|
||||||
- name: prepare web ui
|
- name: prepare web ui
|
||||||
if: steps.cache-web.outputs.cache-hit != 'true'
|
if: steps.cache-web.outputs.cache-hit != 'true'
|
||||||
working-directory: web
|
working-directory: web
|
||||||
@ -208,7 +208,6 @@ jobs:
|
|||||||
npm ci
|
npm ci
|
||||||
make -C .. gen-client-ts
|
make -C .. gen-client-ts
|
||||||
npm run build
|
npm run build
|
||||||
npm run build:sfe
|
|
||||||
- name: run e2e
|
- name: run e2e
|
||||||
run: |
|
run: |
|
||||||
uv run coverage run manage.py test ${{ matrix.job.glob }}
|
uv run coverage run manage.py test ${{ matrix.job.glob }}
|
||||||
|
2
.github/workflows/ci-outpost.yml
vendored
2
.github/workflows/ci-outpost.yml
vendored
@ -29,7 +29,7 @@ jobs:
|
|||||||
- name: Generate API
|
- name: Generate API
|
||||||
run: make gen-client-go
|
run: make gen-client-go
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v8
|
uses: golangci/golangci-lint-action@v7
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: --timeout 5000s --verbose
|
args: --timeout 5000s --verbose
|
||||||
|
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -16,7 +16,7 @@
|
|||||||
],
|
],
|
||||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||||
"typescript.preferences.importModuleSpecifierEnding": "index",
|
"typescript.preferences.importModuleSpecifierEnding": "index",
|
||||||
"typescript.tsdk": "./node_modules/typescript/lib",
|
"typescript.tsdk": "./web/node_modules/typescript/lib",
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||||
"yaml.schemas": {
|
"yaml.schemas": {
|
||||||
"./blueprints/schema.json": "blueprints/**/*.yaml"
|
"./blueprints/schema.json": "blueprints/**/*.yaml"
|
||||||
@ -30,5 +30,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"go.testFlags": ["-count=1"],
|
"go.testFlags": ["-count=1"],
|
||||||
"github-actions.workflows.pinned.workflows": [".github/workflows/ci-main.yml"]
|
"github-actions.workflows.pinned.workflows": [
|
||||||
|
".github/workflows/ci-main.yml"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
10
Dockerfile
10
Dockerfile
@ -40,8 +40,7 @@ COPY ./web /work/web/
|
|||||||
COPY ./website /work/website/
|
COPY ./website /work/website/
|
||||||
COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
|
COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
|
||||||
|
|
||||||
RUN npm run build && \
|
RUN npm run build
|
||||||
npm run build:sfe
|
|
||||||
|
|
||||||
# Stage 3: Build go proxy
|
# Stage 3: Build go proxy
|
||||||
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder
|
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder
|
||||||
@ -86,17 +85,18 @@ FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v7.1.0 AS geoip
|
|||||||
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
|
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
|
||||||
ENV GEOIPUPDATE_VERBOSE="1"
|
ENV GEOIPUPDATE_VERBOSE="1"
|
||||||
ENV GEOIPUPDATE_ACCOUNT_ID_FILE="/run/secrets/GEOIPUPDATE_ACCOUNT_ID"
|
ENV GEOIPUPDATE_ACCOUNT_ID_FILE="/run/secrets/GEOIPUPDATE_ACCOUNT_ID"
|
||||||
|
ENV GEOIPUPDATE_LICENSE_KEY_FILE="/run/secrets/GEOIPUPDATE_LICENSE_KEY"
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
||||||
--mount=type=secret,id=GEOIPUPDATE_LICENSE_KEY \
|
--mount=type=secret,id=GEOIPUPDATE_LICENSE_KEY \
|
||||||
mkdir -p /usr/share/GeoIP && \
|
mkdir -p /usr/share/GeoIP && \
|
||||||
/bin/sh -c "GEOIPUPDATE_LICENSE_KEY_FILE=/run/secrets/GEOIPUPDATE_LICENSE_KEY /usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
|
/bin/sh -c "/usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
|
||||||
|
|
||||||
# Stage 5: Download uv
|
# Stage 5: Download uv
|
||||||
FROM ghcr.io/astral-sh/uv:0.7.4 AS uv
|
FROM ghcr.io/astral-sh/uv:0.7.0 AS uv
|
||||||
# Stage 6: Base python image
|
# Stage 6: Base python image
|
||||||
FROM ghcr.io/goauthentik/fips-python:3.13.3-slim-bookworm-fips AS python-base
|
FROM ghcr.io/goauthentik/fips-python:3.12.10-slim-bookworm-fips AS python-base
|
||||||
|
|
||||||
ENV VENV_PATH="/ak-root/.venv" \
|
ENV VENV_PATH="/ak-root/.venv" \
|
||||||
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
|
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
|
||||||
|
@ -42,4 +42,4 @@ See [SECURITY.md](SECURITY.md)
|
|||||||
|
|
||||||
## Adoption and Contributions
|
## Adoption and Contributions
|
||||||
|
|
||||||
Your organization uses authentik? We'd love to add your logo to the readme and our website! Email us @ hello@goauthentik.io or open a GitHub Issue/PR! For more information on how to contribute to authentik, please refer to our [contribution guide](https://docs.goauthentik.io/docs/developer-docs?utm_source=github).
|
Your organization uses authentik? We'd love to add your logo to the readme and our website! Email us @ hello@goauthentik.io or open a GitHub Issue/PR! For more information on how to contribute to authentik, please refer to our [CONTRIBUTING.md file](./CONTRIBUTING.md).
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
||||||
__version__ = "2025.4.1"
|
__version__ = "2025.4.0"
|
||||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ def create_component(generator: SchemaGenerator, name, schema, type_=ResolvedCom
|
|||||||
return component
|
return component
|
||||||
|
|
||||||
|
|
||||||
def postprocess_schema_responses(result, generator: SchemaGenerator, **kwargs):
|
def postprocess_schema_responses(result, generator: SchemaGenerator, **kwargs): # noqa: W0613
|
||||||
"""Workaround to set a default response for endpoints.
|
"""Workaround to set a default response for endpoints.
|
||||||
Workaround suggested at
|
Workaround suggested at
|
||||||
<https://github.com/tfranzel/drf-spectacular/issues/119#issuecomment-656970357>
|
<https://github.com/tfranzel/drf-spectacular/issues/119#issuecomment-656970357>
|
||||||
|
@ -164,7 +164,9 @@ class BlueprintEntry:
|
|||||||
"""Get the blueprint model, with yaml tags resolved if present"""
|
"""Get the blueprint model, with yaml tags resolved if present"""
|
||||||
return str(self.tag_resolver(self.model, blueprint))
|
return str(self.tag_resolver(self.model, blueprint))
|
||||||
|
|
||||||
def get_permissions(self, blueprint: "Blueprint") -> Generator[BlueprintEntryPermission]:
|
def get_permissions(
|
||||||
|
self, blueprint: "Blueprint"
|
||||||
|
) -> Generator[BlueprintEntryPermission, None, None]:
|
||||||
"""Get permissions of this entry, with all yaml tags resolved"""
|
"""Get permissions of this entry, with all yaml tags resolved"""
|
||||||
for perm in self.permissions:
|
for perm in self.permissions:
|
||||||
yield BlueprintEntryPermission(
|
yield BlueprintEntryPermission(
|
||||||
|
@ -5,10 +5,10 @@ from typing import Any
|
|||||||
from django.db.models import F, Q
|
from django.db.models import F, Q
|
||||||
from django.db.models import Value as V
|
from django.db.models import Value as V
|
||||||
from django.http.request import HttpRequest
|
from django.http.request import HttpRequest
|
||||||
|
from sentry_sdk import get_current_span
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import get_full_version
|
||||||
from authentik.brands.models import Brand
|
from authentik.brands.models import Brand
|
||||||
from authentik.lib.sentry import get_http_meta
|
|
||||||
from authentik.tenants.models import Tenant
|
from authentik.tenants.models import Tenant
|
||||||
|
|
||||||
_q_default = Q(default=True)
|
_q_default = Q(default=True)
|
||||||
@ -32,9 +32,13 @@ def context_processor(request: HttpRequest) -> dict[str, Any]:
|
|||||||
"""Context Processor that injects brand object into every template"""
|
"""Context Processor that injects brand object into every template"""
|
||||||
brand = getattr(request, "brand", DEFAULT_BRAND)
|
brand = getattr(request, "brand", DEFAULT_BRAND)
|
||||||
tenant = getattr(request, "tenant", Tenant())
|
tenant = getattr(request, "tenant", Tenant())
|
||||||
|
trace = ""
|
||||||
|
span = get_current_span()
|
||||||
|
if span:
|
||||||
|
trace = span.to_traceparent()
|
||||||
return {
|
return {
|
||||||
"brand": brand,
|
"brand": brand,
|
||||||
"footer_links": tenant.footer_links,
|
"footer_links": tenant.footer_links,
|
||||||
"html_meta": {**get_http_meta()},
|
"sentry_trace": trace,
|
||||||
"version": get_full_version(),
|
"version": get_full_version(),
|
||||||
}
|
}
|
||||||
|
@ -99,17 +99,18 @@ class GroupSerializer(ModelSerializer):
|
|||||||
if superuser
|
if superuser
|
||||||
else "authentik_core.disable_group_superuser"
|
else "authentik_core.disable_group_superuser"
|
||||||
)
|
)
|
||||||
if self.instance or superuser:
|
has_perm = user.has_perm(perm)
|
||||||
has_perm = user.has_perm(perm) or user.has_perm(perm, self.instance)
|
if self.instance and not has_perm:
|
||||||
if not has_perm:
|
has_perm = user.has_perm(perm, self.instance)
|
||||||
raise ValidationError(
|
if not has_perm:
|
||||||
_(
|
raise ValidationError(
|
||||||
(
|
_(
|
||||||
"User does not have permission to set "
|
(
|
||||||
"superuser status to {superuser_status}."
|
"User does not have permission to set "
|
||||||
).format_map({"superuser_status": superuser})
|
"superuser status to {superuser_status}."
|
||||||
)
|
).format_map({"superuser_status": superuser})
|
||||||
)
|
)
|
||||||
|
)
|
||||||
return superuser
|
return superuser
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.auth.management import create_permissions
|
from django.contrib.auth.management import create_permissions
|
||||||
from django.core.management import call_command
|
|
||||||
from django.core.management.base import BaseCommand, no_translations
|
from django.core.management.base import BaseCommand, no_translations
|
||||||
from guardian.management import create_anonymous_user
|
from guardian.management import create_anonymous_user
|
||||||
|
|
||||||
@ -17,10 +16,6 @@ class Command(BaseCommand):
|
|||||||
"""Check permissions for all apps"""
|
"""Check permissions for all apps"""
|
||||||
for tenant in Tenant.objects.filter(ready=True):
|
for tenant in Tenant.objects.filter(ready=True):
|
||||||
with tenant:
|
with tenant:
|
||||||
# See https://code.djangoproject.com/ticket/28417
|
|
||||||
# Remove potential lingering old permissions
|
|
||||||
call_command("remove_stale_contenttypes", "--no-input")
|
|
||||||
|
|
||||||
for app in apps.get_app_configs():
|
for app in apps.get_app_configs():
|
||||||
self.stdout.write(f"Checking app {app.name} ({app.label})\n")
|
self.stdout.write(f"Checking app {app.name} ({app.label})\n")
|
||||||
create_permissions(app, verbosity=0)
|
create_permissions(app, verbosity=0)
|
||||||
|
@ -1,9 +1,123 @@
|
|||||||
# Generated by Django 5.0.11 on 2025-01-27 12:58
|
# Generated by Django 5.0.11 on 2025-01-27 12:58
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
import pickle # nosec
|
||||||
|
from django.core import signing
|
||||||
|
from django.contrib.auth import BACKEND_SESSION_KEY, HASH_SESSION_KEY, SESSION_KEY
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.sessions.backends.cache import KEY_PREFIX
|
||||||
|
from django.utils.timezone import now, timedelta
|
||||||
|
from authentik.lib.migrations import progress_bar
|
||||||
|
from authentik.root.middleware import ClientIPMiddleware
|
||||||
|
|
||||||
|
|
||||||
|
SESSION_CACHE_ALIAS = "default"
|
||||||
|
|
||||||
|
|
||||||
|
class PickleSerializer:
|
||||||
|
"""
|
||||||
|
Simple wrapper around pickle to be used in signing.dumps()/loads() and
|
||||||
|
cache backends.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, protocol=None):
|
||||||
|
self.protocol = pickle.HIGHEST_PROTOCOL if protocol is None else protocol
|
||||||
|
|
||||||
|
def dumps(self, obj):
|
||||||
|
"""Pickle data to be stored in redis"""
|
||||||
|
return pickle.dumps(obj, self.protocol)
|
||||||
|
|
||||||
|
def loads(self, data):
|
||||||
|
"""Unpickle data to be loaded from redis"""
|
||||||
|
return pickle.loads(data) # nosec
|
||||||
|
|
||||||
|
|
||||||
|
def _migrate_session(
|
||||||
|
apps,
|
||||||
|
db_alias,
|
||||||
|
session_key,
|
||||||
|
session_data,
|
||||||
|
expires,
|
||||||
|
):
|
||||||
|
Session = apps.get_model("authentik_core", "Session")
|
||||||
|
OldAuthenticatedSession = apps.get_model("authentik_core", "OldAuthenticatedSession")
|
||||||
|
AuthenticatedSession = apps.get_model("authentik_core", "AuthenticatedSession")
|
||||||
|
|
||||||
|
old_auth_session = (
|
||||||
|
OldAuthenticatedSession.objects.using(db_alias).filter(session_key=session_key).first()
|
||||||
|
)
|
||||||
|
|
||||||
|
args = {
|
||||||
|
"session_key": session_key,
|
||||||
|
"expires": expires,
|
||||||
|
"last_ip": ClientIPMiddleware.default_ip,
|
||||||
|
"last_user_agent": "",
|
||||||
|
"session_data": {},
|
||||||
|
}
|
||||||
|
for k, v in session_data.items():
|
||||||
|
if k == "authentik/stages/user_login/last_ip":
|
||||||
|
args["last_ip"] = v
|
||||||
|
elif k in ["last_user_agent", "last_used"]:
|
||||||
|
args[k] = v
|
||||||
|
elif args in [SESSION_KEY, BACKEND_SESSION_KEY, HASH_SESSION_KEY]:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
args["session_data"][k] = v
|
||||||
|
if old_auth_session:
|
||||||
|
args["last_user_agent"] = old_auth_session.last_user_agent
|
||||||
|
args["last_used"] = old_auth_session.last_used
|
||||||
|
|
||||||
|
args["session_data"] = pickle.dumps(args["session_data"])
|
||||||
|
session = Session.objects.using(db_alias).create(**args)
|
||||||
|
|
||||||
|
if old_auth_session:
|
||||||
|
AuthenticatedSession.objects.using(db_alias).create(
|
||||||
|
session=session,
|
||||||
|
user=old_auth_session.user,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_redis_sessions(apps, schema_editor):
|
||||||
|
from django.core.cache import caches
|
||||||
|
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
cache = caches[SESSION_CACHE_ALIAS]
|
||||||
|
|
||||||
|
# Not a redis cache, skipping
|
||||||
|
if not hasattr(cache, "keys"):
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\nMigrating Redis sessions to database, this might take a couple of minutes...")
|
||||||
|
for key, session_data in progress_bar(cache.get_many(cache.keys(f"{KEY_PREFIX}*")).items()):
|
||||||
|
_migrate_session(
|
||||||
|
apps=apps,
|
||||||
|
db_alias=db_alias,
|
||||||
|
session_key=key.removeprefix(KEY_PREFIX),
|
||||||
|
session_data=session_data,
|
||||||
|
expires=now() + timedelta(seconds=cache.ttl(key)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_database_sessions(apps, schema_editor):
|
||||||
|
DjangoSession = apps.get_model("sessions", "Session")
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
|
||||||
|
print("\nMigration database sessions, this might take a couple of minutes...")
|
||||||
|
for django_session in progress_bar(DjangoSession.objects.using(db_alias).all()):
|
||||||
|
session_data = signing.loads(
|
||||||
|
django_session.session_data,
|
||||||
|
salt="django.contrib.sessions.SessionStore",
|
||||||
|
serializer=PickleSerializer,
|
||||||
|
)
|
||||||
|
_migrate_session(
|
||||||
|
apps=apps,
|
||||||
|
db_alias=db_alias,
|
||||||
|
session_key=django_session.session_key,
|
||||||
|
session_data=session_data,
|
||||||
|
expires=django_session.expire_date,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
@ -113,4 +227,12 @@ class Migration(migrations.Migration):
|
|||||||
"verbose_name_plural": "Authenticated Sessions",
|
"verbose_name_plural": "Authenticated Sessions",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
code=migrate_redis_sessions,
|
||||||
|
reverse_code=migrations.RunPython.noop,
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
code=migrate_database_sessions,
|
||||||
|
reverse_code=migrations.RunPython.noop,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
# Generated by Django 5.1.9 on 2025-05-14 11:15
|
|
||||||
|
|
||||||
from django.apps.registry import Apps
|
|
||||||
from django.db import migrations
|
|
||||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
|
||||||
|
|
||||||
|
|
||||||
def remove_old_authenticated_session_content_type(
|
|
||||||
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
|
|
||||||
):
|
|
||||||
db_alias = schema_editor.connection.alias
|
|
||||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
|
||||||
|
|
||||||
ContentType.objects.using(db_alias).filter(model="oldauthenticatedsession").delete()
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("authentik_core", "0047_delete_oldauthenticatedsession"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(
|
|
||||||
code=remove_old_authenticated_session_content_type,
|
|
||||||
),
|
|
||||||
]
|
|
@ -21,9 +21,7 @@
|
|||||||
<script src="{% versioned_script 'dist/standalone/loading/index-%v.js' %}" type="module"></script>
|
<script src="{% versioned_script 'dist/standalone/loading/index-%v.js' %}" type="module"></script>
|
||||||
{% block head %}
|
{% block head %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% for key, value in html_meta.items %}
|
<meta name="sentry-trace" content="{{ sentry_trace }}" />
|
||||||
<meta name="{{key}}" content="{{ value }}" />
|
|
||||||
{% endfor %}
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
@ -124,16 +124,6 @@ class TestGroupsAPI(APITestCase):
|
|||||||
{"is_superuser": ["User does not have permission to set superuser status to True."]},
|
{"is_superuser": ["User does not have permission to set superuser status to True."]},
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_superuser_no_perm_no_superuser(self):
|
|
||||||
"""Test creating a group without permission and without superuser flag"""
|
|
||||||
assign_perm("authentik_core.add_group", self.login_user)
|
|
||||||
self.client.force_login(self.login_user)
|
|
||||||
res = self.client.post(
|
|
||||||
reverse("authentik_api:group-list"),
|
|
||||||
data={"name": generate_id(), "is_superuser": False},
|
|
||||||
)
|
|
||||||
self.assertEqual(res.status_code, 201)
|
|
||||||
|
|
||||||
def test_superuser_update_no_perm(self):
|
def test_superuser_update_no_perm(self):
|
||||||
"""Test updating a superuser group without permission"""
|
"""Test updating a superuser group without permission"""
|
||||||
group = Group.objects.create(name=generate_id(), is_superuser=True)
|
group = Group.objects.create(name=generate_id(), is_superuser=True)
|
||||||
|
@ -132,14 +132,13 @@ class LicenseKey:
|
|||||||
"""Get a summarized version of all (not expired) licenses"""
|
"""Get a summarized version of all (not expired) licenses"""
|
||||||
total = LicenseKey(get_license_aud(), 0, "Summarized license", 0, 0)
|
total = LicenseKey(get_license_aud(), 0, "Summarized license", 0, 0)
|
||||||
for lic in License.objects.all():
|
for lic in License.objects.all():
|
||||||
if lic.is_valid:
|
total.internal_users += lic.internal_users
|
||||||
total.internal_users += lic.internal_users
|
total.external_users += lic.external_users
|
||||||
total.external_users += lic.external_users
|
|
||||||
total.license_flags.extend(lic.status.license_flags)
|
|
||||||
exp_ts = int(mktime(lic.expiry.timetuple()))
|
exp_ts = int(mktime(lic.expiry.timetuple()))
|
||||||
if total.exp == 0:
|
if total.exp == 0:
|
||||||
total.exp = exp_ts
|
total.exp = exp_ts
|
||||||
total.exp = max(total.exp, exp_ts)
|
total.exp = max(total.exp, exp_ts)
|
||||||
|
total.license_flags.extend(lic.status.license_flags)
|
||||||
return total
|
return total
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -39,10 +39,6 @@ class License(SerializerModel):
|
|||||||
internal_users = models.BigIntegerField()
|
internal_users = models.BigIntegerField()
|
||||||
external_users = models.BigIntegerField()
|
external_users = models.BigIntegerField()
|
||||||
|
|
||||||
@property
|
|
||||||
def is_valid(self) -> bool:
|
|
||||||
return self.expiry >= now()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serializer(self) -> type[BaseSerializer]:
|
def serializer(self) -> type[BaseSerializer]:
|
||||||
from authentik.enterprise.api import LicenseSerializer
|
from authentik.enterprise.api import LicenseSerializer
|
||||||
|
@ -8,7 +8,6 @@ from django.test import TestCase
|
|||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
||||||
from authentik.core.models import User
|
|
||||||
from authentik.enterprise.license import LicenseKey
|
from authentik.enterprise.license import LicenseKey
|
||||||
from authentik.enterprise.models import (
|
from authentik.enterprise.models import (
|
||||||
THRESHOLD_READ_ONLY_WEEKS,
|
THRESHOLD_READ_ONLY_WEEKS,
|
||||||
@ -72,9 +71,9 @@ class TestEnterpriseLicense(TestCase):
|
|||||||
)
|
)
|
||||||
def test_valid_multiple(self):
|
def test_valid_multiple(self):
|
||||||
"""Check license verification"""
|
"""Check license verification"""
|
||||||
lic = License.objects.create(key=generate_id(), expiry=expiry_valid)
|
lic = License.objects.create(key=generate_id())
|
||||||
self.assertTrue(lic.status.status().is_valid)
|
self.assertTrue(lic.status.status().is_valid)
|
||||||
lic2 = License.objects.create(key=generate_id(), expiry=expiry_valid)
|
lic2 = License.objects.create(key=generate_id())
|
||||||
self.assertTrue(lic2.status.status().is_valid)
|
self.assertTrue(lic2.status.status().is_valid)
|
||||||
total = LicenseKey.get_total()
|
total = LicenseKey.get_total()
|
||||||
self.assertEqual(total.internal_users, 200)
|
self.assertEqual(total.internal_users, 200)
|
||||||
@ -233,9 +232,7 @@ class TestEnterpriseLicense(TestCase):
|
|||||||
)
|
)
|
||||||
def test_expiry_expired(self):
|
def test_expiry_expired(self):
|
||||||
"""Check license verification"""
|
"""Check license verification"""
|
||||||
User.objects.all().delete()
|
License.objects.create(key=generate_id())
|
||||||
License.objects.all().delete()
|
|
||||||
License.objects.create(key=generate_id(), expiry=expiry_expired)
|
|
||||||
self.assertEqual(LicenseKey.get_total().summary().status, LicenseUsageStatus.EXPIRED)
|
self.assertEqual(LicenseKey.get_total().summary().status, LicenseUsageStatus.EXPIRED)
|
||||||
|
|
||||||
@patch(
|
@patch(
|
||||||
|
@ -57,7 +57,7 @@ class LogEventSerializer(PassiveSerializer):
|
|||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def capture_logs(log_default_output=True) -> Generator[list[LogEvent]]:
|
def capture_logs(log_default_output=True) -> Generator[list[LogEvent], None, None]:
|
||||||
"""Capture log entries created"""
|
"""Capture log entries created"""
|
||||||
logs = []
|
logs = []
|
||||||
cap = LogCapture()
|
cap = LogCapture()
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'dist/sfe/bootstrap.min.css' %}">
|
<link rel="stylesheet" type="text/css" href="{% static 'dist/sfe/bootstrap.min.css' %}">
|
||||||
<meta name="sentry-trace" content="{{ sentry_trace }}" />
|
<meta name="sentry-trace" content="{{ sentry_trace }}" />
|
||||||
<link rel="prefetch" href="{{ flow_background_url }}" />
|
|
||||||
{% include "base/header_js.html" %}
|
{% include "base/header_js.html" %}
|
||||||
<style>
|
<style>
|
||||||
html,
|
html,
|
||||||
@ -23,7 +22,7 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
background-image: url("{{ flow_background_url }}");
|
background-image: url("{{ flow.background_url }}");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
{% block head_before %}
|
{% block head_before %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<link rel="prefetch" href="{{ flow_background_url }}" />
|
<link rel="prefetch" href="{{ flow.background_url }}" />
|
||||||
{% if flow.compatibility_mode and not inspector %}
|
{% if flow.compatibility_mode and not inspector %}
|
||||||
<script>ShadyDOM = { force: true };</script>
|
<script>ShadyDOM = { force: !navigator.webdriver };</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% include "base/header_js.html" %}
|
{% include "base/header_js.html" %}
|
||||||
<script>
|
<script>
|
||||||
@ -21,7 +21,7 @@ window.authentik.flow = {
|
|||||||
<script src="{% versioned_script 'dist/flow/FlowInterface-%v.js' %}" type="module"></script>
|
<script src="{% versioned_script 'dist/flow/FlowInterface-%v.js' %}" type="module"></script>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--ak-flow-background: url("{{ flow_background_url }}");
|
--ak-flow-background: url("{{ flow.background_url }}");
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -13,9 +13,7 @@ class FlowInterfaceView(InterfaceView):
|
|||||||
"""Flow interface"""
|
"""Flow interface"""
|
||||||
|
|
||||||
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
||||||
flow = get_object_or_404(Flow, slug=self.kwargs.get("flow_slug"))
|
kwargs["flow"] = get_object_or_404(Flow, slug=self.kwargs.get("flow_slug"))
|
||||||
kwargs["flow"] = flow
|
|
||||||
kwargs["flow_background_url"] = flow.background_url(self.request)
|
|
||||||
kwargs["inspector"] = "inspector" in self.request.GET
|
kwargs["inspector"] = "inspector" in self.request.GET
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
@ -363,9 +363,6 @@ def django_db_config(config: ConfigLoader | None = None) -> dict:
|
|||||||
pool_options = config.get_dict_from_b64_json("postgresql.pool_options", True)
|
pool_options = config.get_dict_from_b64_json("postgresql.pool_options", True)
|
||||||
if not pool_options:
|
if not pool_options:
|
||||||
pool_options = True
|
pool_options = True
|
||||||
# FIXME: Temporarily force pool to be deactivated.
|
|
||||||
# See https://github.com/goauthentik/authentik/issues/14320
|
|
||||||
pool_options = False
|
|
||||||
|
|
||||||
db = {
|
db = {
|
||||||
"default": {
|
"default": {
|
||||||
|
@ -17,7 +17,7 @@ from ldap3.core.exceptions import LDAPException
|
|||||||
from redis.exceptions import ConnectionError as RedisConnectionError
|
from redis.exceptions import ConnectionError as RedisConnectionError
|
||||||
from redis.exceptions import RedisError, ResponseError
|
from redis.exceptions import RedisError, ResponseError
|
||||||
from rest_framework.exceptions import APIException
|
from rest_framework.exceptions import APIException
|
||||||
from sentry_sdk import HttpTransport, get_current_scope
|
from sentry_sdk import HttpTransport
|
||||||
from sentry_sdk import init as sentry_sdk_init
|
from sentry_sdk import init as sentry_sdk_init
|
||||||
from sentry_sdk.api import set_tag
|
from sentry_sdk.api import set_tag
|
||||||
from sentry_sdk.integrations.argv import ArgvIntegration
|
from sentry_sdk.integrations.argv import ArgvIntegration
|
||||||
@ -27,7 +27,6 @@ from sentry_sdk.integrations.redis import RedisIntegration
|
|||||||
from sentry_sdk.integrations.socket import SocketIntegration
|
from sentry_sdk.integrations.socket import SocketIntegration
|
||||||
from sentry_sdk.integrations.stdlib import StdlibIntegration
|
from sentry_sdk.integrations.stdlib import StdlibIntegration
|
||||||
from sentry_sdk.integrations.threading import ThreadingIntegration
|
from sentry_sdk.integrations.threading import ThreadingIntegration
|
||||||
from sentry_sdk.tracing import BAGGAGE_HEADER_NAME, SENTRY_TRACE_HEADER_NAME
|
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
from websockets.exceptions import WebSocketException
|
from websockets.exceptions import WebSocketException
|
||||||
|
|
||||||
@ -96,8 +95,6 @@ def traces_sampler(sampling_context: dict) -> float:
|
|||||||
return 0
|
return 0
|
||||||
if _type == "websocket":
|
if _type == "websocket":
|
||||||
return 0
|
return 0
|
||||||
if CONFIG.get_bool("debug"):
|
|
||||||
return 1
|
|
||||||
return float(CONFIG.get("error_reporting.sample_rate", 0.1))
|
return float(CONFIG.get("error_reporting.sample_rate", 0.1))
|
||||||
|
|
||||||
|
|
||||||
@ -170,14 +167,3 @@ def before_send(event: dict, hint: dict) -> dict | None:
|
|||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
return None
|
return None
|
||||||
return event
|
return event
|
||||||
|
|
||||||
|
|
||||||
def get_http_meta():
|
|
||||||
"""Get sentry-related meta key-values"""
|
|
||||||
scope = get_current_scope()
|
|
||||||
meta = {
|
|
||||||
SENTRY_TRACE_HEADER_NAME: scope.get_traceparent() or "",
|
|
||||||
}
|
|
||||||
if bag := scope.get_baggage():
|
|
||||||
meta[BAGGAGE_HEADER_NAME] = bag.serialize()
|
|
||||||
return meta
|
|
||||||
|
@ -59,7 +59,7 @@ class PropertyMappingManager:
|
|||||||
request: HttpRequest | None,
|
request: HttpRequest | None,
|
||||||
return_mapping: bool = False,
|
return_mapping: bool = False,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> Generator[tuple[dict, PropertyMapping]]:
|
) -> Generator[tuple[dict, PropertyMapping], None]:
|
||||||
"""Iterate over all mappings that were pre-compiled and
|
"""Iterate over all mappings that were pre-compiled and
|
||||||
execute all of them with the given context"""
|
execute all of them with the given context"""
|
||||||
if not self.__has_compiled:
|
if not self.__has_compiled:
|
||||||
|
@ -494,88 +494,86 @@ class TestConfig(TestCase):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# FIXME: Temporarily force pool to be deactivated.
|
def test_db_pool(self):
|
||||||
# See https://github.com/goauthentik/authentik/issues/14320
|
"""Test DB Config with pool"""
|
||||||
# def test_db_pool(self):
|
config = ConfigLoader()
|
||||||
# """Test DB Config with pool"""
|
config.set("postgresql.host", "foo")
|
||||||
# config = ConfigLoader()
|
config.set("postgresql.name", "foo")
|
||||||
# config.set("postgresql.host", "foo")
|
config.set("postgresql.user", "foo")
|
||||||
# config.set("postgresql.name", "foo")
|
config.set("postgresql.password", "foo")
|
||||||
# config.set("postgresql.user", "foo")
|
config.set("postgresql.port", "foo")
|
||||||
# config.set("postgresql.password", "foo")
|
config.set("postgresql.test.name", "foo")
|
||||||
# config.set("postgresql.port", "foo")
|
config.set("postgresql.use_pool", True)
|
||||||
# config.set("postgresql.test.name", "foo")
|
conf = django_db_config(config)
|
||||||
# config.set("postgresql.use_pool", True)
|
self.assertEqual(
|
||||||
# conf = django_db_config(config)
|
conf,
|
||||||
# self.assertEqual(
|
{
|
||||||
# conf,
|
"default": {
|
||||||
# {
|
"ENGINE": "authentik.root.db",
|
||||||
# "default": {
|
"HOST": "foo",
|
||||||
# "ENGINE": "authentik.root.db",
|
"NAME": "foo",
|
||||||
# "HOST": "foo",
|
"OPTIONS": {
|
||||||
# "NAME": "foo",
|
"pool": True,
|
||||||
# "OPTIONS": {
|
"sslcert": None,
|
||||||
# "pool": True,
|
"sslkey": None,
|
||||||
# "sslcert": None,
|
"sslmode": None,
|
||||||
# "sslkey": None,
|
"sslrootcert": None,
|
||||||
# "sslmode": None,
|
},
|
||||||
# "sslrootcert": None,
|
"PASSWORD": "foo",
|
||||||
# },
|
"PORT": "foo",
|
||||||
# "PASSWORD": "foo",
|
"TEST": {"NAME": "foo"},
|
||||||
# "PORT": "foo",
|
"USER": "foo",
|
||||||
# "TEST": {"NAME": "foo"},
|
"CONN_MAX_AGE": 0,
|
||||||
# "USER": "foo",
|
"CONN_HEALTH_CHECKS": False,
|
||||||
# "CONN_MAX_AGE": 0,
|
"DISABLE_SERVER_SIDE_CURSORS": False,
|
||||||
# "CONN_HEALTH_CHECKS": False,
|
}
|
||||||
# "DISABLE_SERVER_SIDE_CURSORS": False,
|
},
|
||||||
# }
|
)
|
||||||
# },
|
|
||||||
# )
|
|
||||||
|
|
||||||
# def test_db_pool_options(self):
|
def test_db_pool_options(self):
|
||||||
# """Test DB Config with pool"""
|
"""Test DB Config with pool"""
|
||||||
# config = ConfigLoader()
|
config = ConfigLoader()
|
||||||
# config.set("postgresql.host", "foo")
|
config.set("postgresql.host", "foo")
|
||||||
# config.set("postgresql.name", "foo")
|
config.set("postgresql.name", "foo")
|
||||||
# config.set("postgresql.user", "foo")
|
config.set("postgresql.user", "foo")
|
||||||
# config.set("postgresql.password", "foo")
|
config.set("postgresql.password", "foo")
|
||||||
# config.set("postgresql.port", "foo")
|
config.set("postgresql.port", "foo")
|
||||||
# config.set("postgresql.test.name", "foo")
|
config.set("postgresql.test.name", "foo")
|
||||||
# config.set("postgresql.use_pool", True)
|
config.set("postgresql.use_pool", True)
|
||||||
# config.set(
|
config.set(
|
||||||
# "postgresql.pool_options",
|
"postgresql.pool_options",
|
||||||
# base64.b64encode(
|
base64.b64encode(
|
||||||
# dumps(
|
dumps(
|
||||||
# {
|
{
|
||||||
# "max_size": 15,
|
"max_size": 15,
|
||||||
# }
|
}
|
||||||
# ).encode()
|
).encode()
|
||||||
# ).decode(),
|
).decode(),
|
||||||
# )
|
)
|
||||||
# conf = django_db_config(config)
|
conf = django_db_config(config)
|
||||||
# self.assertEqual(
|
self.assertEqual(
|
||||||
# conf,
|
conf,
|
||||||
# {
|
{
|
||||||
# "default": {
|
"default": {
|
||||||
# "ENGINE": "authentik.root.db",
|
"ENGINE": "authentik.root.db",
|
||||||
# "HOST": "foo",
|
"HOST": "foo",
|
||||||
# "NAME": "foo",
|
"NAME": "foo",
|
||||||
# "OPTIONS": {
|
"OPTIONS": {
|
||||||
# "pool": {
|
"pool": {
|
||||||
# "max_size": 15,
|
"max_size": 15,
|
||||||
# },
|
},
|
||||||
# "sslcert": None,
|
"sslcert": None,
|
||||||
# "sslkey": None,
|
"sslkey": None,
|
||||||
# "sslmode": None,
|
"sslmode": None,
|
||||||
# "sslrootcert": None,
|
"sslrootcert": None,
|
||||||
# },
|
},
|
||||||
# "PASSWORD": "foo",
|
"PASSWORD": "foo",
|
||||||
# "PORT": "foo",
|
"PORT": "foo",
|
||||||
# "TEST": {"NAME": "foo"},
|
"TEST": {"NAME": "foo"},
|
||||||
# "USER": "foo",
|
"USER": "foo",
|
||||||
# "CONN_MAX_AGE": 0,
|
"CONN_MAX_AGE": 0,
|
||||||
# "CONN_HEALTH_CHECKS": False,
|
"CONN_HEALTH_CHECKS": False,
|
||||||
# "DISABLE_SERVER_SIDE_CURSORS": False,
|
"DISABLE_SERVER_SIDE_CURSORS": False,
|
||||||
# }
|
}
|
||||||
# },
|
},
|
||||||
# )
|
)
|
||||||
|
@ -199,7 +199,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMProviderGroup, SCIMGroupSchema]):
|
|||||||
chunk_size = len(ops)
|
chunk_size = len(ops)
|
||||||
if len(ops) < 1:
|
if len(ops) < 1:
|
||||||
return
|
return
|
||||||
for chunk in batched(ops, chunk_size, strict=False):
|
for chunk in batched(ops, chunk_size):
|
||||||
req = PatchRequest(Operations=list(chunk))
|
req = PatchRequest(Operations=list(chunk))
|
||||||
self._request(
|
self._request(
|
||||||
"PATCH",
|
"PATCH",
|
||||||
|
@ -317,7 +317,7 @@ class KerberosSource(Source):
|
|||||||
usage="accept", name=name, store=self.get_gssapi_store()
|
usage="accept", name=name, store=self.get_gssapi_store()
|
||||||
)
|
)
|
||||||
except gssapi.exceptions.GSSError as exc:
|
except gssapi.exceptions.GSSError as exc:
|
||||||
LOGGER.warning("GSSAPI credentials failure", exc=exc)
|
LOGGER.warn("GSSAPI credentials failure", exc=exc)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
|||||||
"$schema": "http://json-schema.org/draft-07/schema",
|
"$schema": "http://json-schema.org/draft-07/schema",
|
||||||
"$id": "https://goauthentik.io/blueprints/schema.json",
|
"$id": "https://goauthentik.io/blueprints/schema.json",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "authentik 2025.4.1 Blueprint schema",
|
"title": "authentik 2025.4.0 Blueprint schema",
|
||||||
"required": [
|
"required": [
|
||||||
"version",
|
"version",
|
||||||
"entries"
|
"entries"
|
||||||
|
@ -31,7 +31,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- redis:/data
|
- redis:/data
|
||||||
server:
|
server:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.4.1}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.4.0}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: server
|
command: server
|
||||||
environment:
|
environment:
|
||||||
@ -55,7 +55,7 @@ services:
|
|||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
worker:
|
worker:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.4.1}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.4.0}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: worker
|
command: worker
|
||||||
environment:
|
environment:
|
||||||
|
16
go.mod
16
go.mod
@ -5,7 +5,7 @@ go 1.24.0
|
|||||||
require (
|
require (
|
||||||
beryju.io/ldap v0.1.0
|
beryju.io/ldap v0.1.0
|
||||||
github.com/coreos/go-oidc/v3 v3.14.1
|
github.com/coreos/go-oidc/v3 v3.14.1
|
||||||
github.com/getsentry/sentry-go v0.33.0
|
github.com/getsentry/sentry-go v0.32.0
|
||||||
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
||||||
github.com/go-ldap/ldap/v3 v3.4.11
|
github.com/go-ldap/ldap/v3 v3.4.11
|
||||||
github.com/go-openapi/runtime v0.28.0
|
github.com/go-openapi/runtime v0.28.0
|
||||||
@ -19,18 +19,18 @@ require (
|
|||||||
github.com/jellydator/ttlcache/v3 v3.3.0
|
github.com/jellydator/ttlcache/v3 v3.3.0
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
||||||
github.com/pires/go-proxyproto v0.8.1
|
github.com/pires/go-proxyproto v0.8.0
|
||||||
github.com/prometheus/client_golang v1.22.0
|
github.com/prometheus/client_golang v1.22.0
|
||||||
github.com/redis/go-redis/v9 v9.8.0
|
github.com/redis/go-redis/v9 v9.7.3
|
||||||
github.com/sethvargo/go-envconfig v1.3.0
|
github.com/sethvargo/go-envconfig v1.2.0
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/spf13/cobra v1.9.1
|
github.com/spf13/cobra v1.9.1
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/wwt/guac v1.3.2
|
github.com/wwt/guac v1.3.2
|
||||||
goauthentik.io/api/v3 v3.2025041.1
|
goauthentik.io/api/v3 v3.2025024.9
|
||||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||||
golang.org/x/oauth2 v0.30.0
|
golang.org/x/oauth2 v0.29.0
|
||||||
golang.org/x/sync v0.14.0
|
golang.org/x/sync v0.13.0
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
|
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
|
||||||
)
|
)
|
||||||
@ -75,7 +75,7 @@ require (
|
|||||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||||
golang.org/x/crypto v0.36.0 // indirect
|
golang.org/x/crypto v0.36.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
golang.org/x/text v0.24.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.5 // indirect
|
google.golang.org/protobuf v1.36.5 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
36
go.sum
36
go.sum
@ -69,8 +69,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/getsentry/sentry-go v0.33.0 h1:YWyDii0KGVov3xOaamOnF0mjOrqSjBqwv48UEzn7QFg=
|
github.com/getsentry/sentry-go v0.32.0 h1:YKs+//QmwE3DcYtfKRH8/KyOOF/I6Qnx7qYGNHCGmCY=
|
||||||
github.com/getsentry/sentry-go v0.33.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
|
github.com/getsentry/sentry-go v0.32.0/go.mod h1:CYNcMMz73YigoHljQRG+qPF+eMq8gG72XcGN/p71BAY=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
@ -230,8 +230,8 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+
|
|||||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0=
|
||||||
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@ -245,14 +245,14 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ
|
|||||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
|
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||||
github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sethvargo/go-envconfig v1.3.0 h1:gJs+Fuv8+f05omTpwWIu6KmuseFAXKrIaOZSh8RMt0U=
|
github.com/sethvargo/go-envconfig v1.2.0 h1:q3XkOZWkC+G1sMLCrw9oPGTjYexygLOXDmGUit1ti8Q=
|
||||||
github.com/sethvargo/go-envconfig v1.3.0/go.mod h1:JLd0KFWQYzyENqnEPWWZ49i4vzZo/6nRidxI8YvGiHw=
|
github.com/sethvargo/go-envconfig v1.2.0/go.mod h1:JLd0KFWQYzyENqnEPWWZ49i4vzZo/6nRidxI8YvGiHw=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
@ -290,8 +290,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
|
|||||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
goauthentik.io/api/v3 v3.2025041.1 h1:GAN6AoTmfnCGgx1SyM07jP4/LR/T3rkTEyShSBd3Co8=
|
goauthentik.io/api/v3 v3.2025024.9 h1:i3tbkyotE32ZpJ729BsPWTuLQUdtZ54Li4aP1amZzsM=
|
||||||
goauthentik.io/api/v3 v3.2025041.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
goauthentik.io/api/v3 v3.2025024.9/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@ -358,16 +358,16 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
|
|||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -376,8 +376,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -412,8 +412,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -29,4 +29,4 @@ func UserAgent() string {
|
|||||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSION = "2025.4.1"
|
const VERSION = "2025.4.0"
|
||||||
|
@ -56,7 +56,6 @@ EXPOSE 3389 6636 9300
|
|||||||
|
|
||||||
USER 1000
|
USER 1000
|
||||||
|
|
||||||
ENV TMPDIR=/dev/shm/ \
|
ENV GOFIPS=1
|
||||||
GOFIPS=1
|
|
||||||
|
|
||||||
ENTRYPOINT ["/ldap"]
|
ENTRYPOINT ["/ldap"]
|
||||||
|
@ -97,7 +97,6 @@ elif [[ "$1" == "test-all" ]]; then
|
|||||||
elif [[ "$1" == "healthcheck" ]]; then
|
elif [[ "$1" == "healthcheck" ]]; then
|
||||||
run_authentik healthcheck $(cat $MODE_FILE)
|
run_authentik healthcheck $(cat $MODE_FILE)
|
||||||
elif [[ "$1" == "dump_config" ]]; then
|
elif [[ "$1" == "dump_config" ]]; then
|
||||||
shift
|
|
||||||
exec python -m authentik.lib.config $@
|
exec python -m authentik.lib.config $@
|
||||||
elif [[ "$1" == "debug" ]]; then
|
elif [[ "$1" == "debug" ]]; then
|
||||||
exec sleep infinity
|
exec sleep infinity
|
||||||
|
8
lifecycle/aws/package-lock.json
generated
8
lifecycle/aws/package-lock.json
generated
@ -9,7 +9,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aws-cdk": "^2.1015.0",
|
"aws-cdk": "^2.1012.0",
|
||||||
"cross-env": "^7.0.3"
|
"cross-env": "^7.0.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -17,9 +17,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/aws-cdk": {
|
"node_modules/aws-cdk": {
|
||||||
"version": "2.1015.0",
|
"version": "2.1012.0",
|
||||||
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1015.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1012.0.tgz",
|
||||||
"integrity": "sha512-txd+yMVVybtLfiwT409+fahbP0SkiwhmQvQf6PVVYnWzDPSknxYlUNJHisHV4tJEcbHWn1QPsLmqqMT0bw8hBg==",
|
"integrity": "sha512-C6jSWkqP0hkY2Cs300VJHjspmTXDTMfB813kwZvRbd/OsKBfTBJBbYU16VoLAp1LVEOnQMf8otSlaSgzVF0X9A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aws-cdk": "^2.1015.0",
|
"aws-cdk": "^2.1012.0",
|
||||||
"cross-env": "^7.0.3"
|
"cross-env": "^7.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ Parameters:
|
|||||||
Description: authentik Docker image
|
Description: authentik Docker image
|
||||||
AuthentikVersion:
|
AuthentikVersion:
|
||||||
Type: String
|
Type: String
|
||||||
Default: 2025.4.1
|
Default: 2025.4.0
|
||||||
Description: authentik Docker image tag
|
Description: authentik Docker image tag
|
||||||
AuthentikServerCPU:
|
AuthentikServerCPU:
|
||||||
Type: Number
|
Type: Number
|
||||||
|
Binary file not shown.
@ -12,8 +12,8 @@
|
|||||||
# tmassimi, 2024
|
# tmassimi, 2024
|
||||||
# Marc Schmitt, 2024
|
# Marc Schmitt, 2024
|
||||||
# albanobattistella <albanobattistella@gmail.com>, 2024
|
# albanobattistella <albanobattistella@gmail.com>, 2024
|
||||||
# Matteo Piccina <altermatte@gmail.com>, 2025
|
|
||||||
# Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025
|
# Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025
|
||||||
|
# Matteo Piccina <altermatte@gmail.com>, 2025
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -22,7 +22,7 @@ msgstr ""
|
|||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
|
"POT-Creation-Date: 2025-04-23 09:00+0000\n"
|
||||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||||
"Last-Translator: Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025\n"
|
"Last-Translator: Matteo Piccina <altermatte@gmail.com>, 2025\n"
|
||||||
"Language-Team: Italian (https://app.transifex.com/authentik/teams/119923/it/)\n"
|
"Language-Team: Italian (https://app.transifex.com/authentik/teams/119923/it/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@ -383,7 +383,7 @@ msgstr "Mappatura delle proprietà"
|
|||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "session data"
|
msgid "session data"
|
||||||
msgstr "dati sessione"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "Session"
|
msgid "Session"
|
||||||
@ -509,7 +509,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "Number of passwords to check against."
|
msgid "Number of passwords to check against."
|
||||||
msgstr "Numero di password da verificare."
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
#: authentik/policies/password/models.py
|
#: authentik/policies/password/models.py
|
||||||
@ -519,19 +519,18 @@ msgstr "Password non impostata nel contesto"
|
|||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "This password has been used previously. Please choose a different one."
|
msgid "This password has been used previously. Please choose a different one."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Questa password è già stata utilizzata in precedenza. Scegline una diversa."
|
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "Password Uniqueness Policy"
|
msgid "Password Uniqueness Policy"
|
||||||
msgstr "Politica di unicità della password"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "Password Uniqueness Policies"
|
msgid "Password Uniqueness Policies"
|
||||||
msgstr "Criteri di unicità delle password"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/policies/unique_password/models.py
|
#: authentik/enterprise/policies/unique_password/models.py
|
||||||
msgid "User Password History"
|
msgid "User Password History"
|
||||||
msgstr "Cronologia password utente"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/enterprise/policy.py
|
#: authentik/enterprise/policy.py
|
||||||
msgid "Enterprise required to access this feature."
|
msgid "Enterprise required to access this feature."
|
||||||
@ -2204,7 +2203,7 @@ msgstr "Ruoli"
|
|||||||
|
|
||||||
#: authentik/rbac/models.py
|
#: authentik/rbac/models.py
|
||||||
msgid "Initial Permissions"
|
msgid "Initial Permissions"
|
||||||
msgstr "Permessi Iniziali"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/rbac/models.py
|
#: authentik/rbac/models.py
|
||||||
msgid "System permission"
|
msgid "System permission"
|
||||||
@ -2459,9 +2458,6 @@ msgid ""
|
|||||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||||
"Active Directory"
|
"Active Directory"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Cerca l'appartenenza al gruppo in base a un attributo utente anziché a un "
|
|
||||||
"attributo di gruppo. Questo consente la risoluzione di gruppi nidificati su "
|
|
||||||
"sistemi come FreeIPA e Active Directory."
|
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "LDAP Source"
|
msgid "LDAP Source"
|
||||||
@ -2481,19 +2477,19 @@ msgstr "Mappature delle proprietà della sorgente LDAP"
|
|||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "User LDAP Source Connection"
|
msgid "User LDAP Source Connection"
|
||||||
msgstr "Connessione Sorgente LDAP Utente"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "User LDAP Source Connections"
|
msgid "User LDAP Source Connections"
|
||||||
msgstr "Connessioni Sorgente LDAP Utente"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "Group LDAP Source Connection"
|
msgid "Group LDAP Source Connection"
|
||||||
msgstr "Connessione Sorgente LDAP Gruppo"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid "Group LDAP Source Connections"
|
msgid "Group LDAP Source Connections"
|
||||||
msgstr "Connessioni Sorgente LDAP Gruppo"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/ldap/signals.py
|
#: authentik/sources/ldap/signals.py
|
||||||
msgid "Password does not match Active Directory Complexity."
|
msgid "Password does not match Active Directory Complexity."
|
||||||
@ -2505,11 +2501,11 @@ msgstr "Nessun token ricevuto."
|
|||||||
|
|
||||||
#: authentik/sources/oauth/models.py
|
#: authentik/sources/oauth/models.py
|
||||||
msgid "HTTP Basic Authentication"
|
msgid "HTTP Basic Authentication"
|
||||||
msgstr "HTTP Basic Authentication"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py
|
#: authentik/sources/oauth/models.py
|
||||||
msgid "Include the client ID and secret as request parameters"
|
msgid "Include the client ID and secret as request parameters"
|
||||||
msgstr "Includi il client ID e il segreto come parametri di richiesta"
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py
|
#: authentik/sources/oauth/models.py
|
||||||
msgid "Request Token URL"
|
msgid "Request Token URL"
|
||||||
@ -2556,8 +2552,6 @@ msgid ""
|
|||||||
"How to perform authentication during an authorization_code token request "
|
"How to perform authentication during an authorization_code token request "
|
||||||
"flow"
|
"flow"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Come eseguire l'autenticazione durante un flusso di richiesta del token "
|
|
||||||
"authorization_code"
|
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py
|
#: authentik/sources/oauth/models.py
|
||||||
msgid "OAuth Source"
|
msgid "OAuth Source"
|
||||||
@ -3490,9 +3484,6 @@ msgid ""
|
|||||||
"Show the user the 'Remember me on this device' toggle, allowing repeat users"
|
"Show the user the 'Remember me on this device' toggle, allowing repeat users"
|
||||||
" to skip straight to entering their password."
|
" to skip straight to entering their password."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Mostra all'utente il pulsante \"Ricordami su questo dispositivo\", "
|
|
||||||
"consentendo agli utenti abituali di passare direttamente all'inserimento "
|
|
||||||
"della password."
|
|
||||||
|
|
||||||
#: authentik/stages/identification/models.py
|
#: authentik/stages/identification/models.py
|
||||||
msgid "Optional enrollment flow, which is linked at the bottom of the page."
|
msgid "Optional enrollment flow, which is linked at the bottom of the page."
|
||||||
@ -3882,11 +3873,11 @@ msgstr ""
|
|||||||
|
|
||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "Reputation cannot decrease lower than this value. Zero or negative."
|
msgid "Reputation cannot decrease lower than this value. Zero or negative."
|
||||||
msgstr "La reputazione non può scendere sotto questo valore. Zero o negativo."
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "Reputation cannot increase higher than this value. Zero or positive."
|
msgid "Reputation cannot increase higher than this value. Zero or positive."
|
||||||
msgstr "La reputazione non può superare questo valore. Zero o positivo."
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "The option configures the footer links on the flow executor pages."
|
msgid "The option configures the footer links on the flow executor pages."
|
||||||
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
538
package-lock.json
generated
538
package-lock.json
generated
@ -1,546 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.4.0",
|
"version": "2025.2.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.4.0",
|
"version": "2025.2.1"
|
||||||
"devDependencies": {
|
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
|
||||||
"prettier": "^3.3.3",
|
|
||||||
"prettier-plugin-organize-imports": "^4.1.0",
|
|
||||||
"prettier-plugin-packagejson": "^2.5.10",
|
|
||||||
"typescript": "^5.6.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/code-frame": {
|
|
||||||
"version": "7.26.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
|
|
||||||
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/helper-validator-identifier": "^7.25.9",
|
|
||||||
"js-tokens": "^4.0.0",
|
|
||||||
"picocolors": "^1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/generator": {
|
|
||||||
"version": "7.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz",
|
|
||||||
"integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/parser": "^7.27.0",
|
|
||||||
"@babel/types": "^7.27.0",
|
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.25",
|
|
||||||
"jsesc": "^3.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/helper-string-parser": {
|
|
||||||
"version": "7.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
|
|
||||||
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
|
||||||
"version": "7.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
|
|
||||||
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/parser": {
|
|
||||||
"version": "7.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
|
|
||||||
"integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/types": "^7.27.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"parser": "bin/babel-parser.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/template": {
|
|
||||||
"version": "7.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
|
|
||||||
"integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/code-frame": "^7.26.2",
|
|
||||||
"@babel/parser": "^7.27.0",
|
|
||||||
"@babel/types": "^7.27.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/traverse": {
|
|
||||||
"version": "7.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz",
|
|
||||||
"integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/code-frame": "^7.26.2",
|
|
||||||
"@babel/generator": "^7.27.0",
|
|
||||||
"@babel/parser": "^7.27.0",
|
|
||||||
"@babel/template": "^7.27.0",
|
|
||||||
"@babel/types": "^7.27.0",
|
|
||||||
"debug": "^4.3.1",
|
|
||||||
"globals": "^11.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/types": {
|
|
||||||
"version": "7.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
|
|
||||||
"integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/helper-string-parser": "^7.25.9",
|
|
||||||
"@babel/helper-validator-identifier": "^7.25.9"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
|
||||||
"version": "0.3.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
|
||||||
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/set-array": "^1.2.1",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.24"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/resolve-uri": {
|
|
||||||
"version": "3.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
|
||||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/set-array": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
|
||||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
|
||||||
"version": "1.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
|
||||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
|
||||||
"version": "0.3.25",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
|
||||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/resolve-uri": "^3.1.0",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@pkgr/core": {
|
|
||||||
"version": "0.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.2.tgz",
|
|
||||||
"integrity": "sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/unts"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@trivago/prettier-plugin-sort-imports": {
|
|
||||||
"version": "5.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-5.2.2.tgz",
|
|
||||||
"integrity": "sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/generator": "^7.26.5",
|
|
||||||
"@babel/parser": "^7.26.7",
|
|
||||||
"@babel/traverse": "^7.26.7",
|
|
||||||
"@babel/types": "^7.26.7",
|
|
||||||
"javascript-natural-sort": "^0.7.1",
|
|
||||||
"lodash": "^4.17.21"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">18.12"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@vue/compiler-sfc": "3.x",
|
|
||||||
"prettier": "2.x - 3.x",
|
|
||||||
"prettier-plugin-svelte": "3.x",
|
|
||||||
"svelte": "4.x || 5.x"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@vue/compiler-sfc": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"prettier-plugin-svelte": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"svelte": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/debug": {
|
|
||||||
"version": "4.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
|
||||||
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "^2.1.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"supports-color": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/detect-indent": {
|
|
||||||
"version": "7.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.1.tgz",
|
|
||||||
"integrity": "sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/detect-newline": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz",
|
|
||||||
"integrity": "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fdir": {
|
|
||||||
"version": "6.4.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
|
|
||||||
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"peerDependencies": {
|
|
||||||
"picomatch": "^3 || ^4"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"picomatch": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/get-stdin": {
|
|
||||||
"version": "9.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz",
|
|
||||||
"integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/git-hooks-list": {
|
|
||||||
"version": "3.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-3.2.0.tgz",
|
|
||||||
"integrity": "sha512-ZHG9a1gEhUMX1TvGrLdyWb9kDopCBbTnI8z4JgRMYxsijWipgjSEYoPWqBuIB0DnRnvqlQSEeVmzpeuPm7NdFQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/fisker/git-hooks-list?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/globals": {
|
|
||||||
"version": "11.12.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
|
||||||
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-plain-obj": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
|
|
||||||
"integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/javascript-natural-sort": {
|
|
||||||
"version": "0.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
|
|
||||||
"integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/js-tokens": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/jsesc": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"jsesc": "bin/jsesc"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lodash": {
|
|
||||||
"version": "4.17.21",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/ms": {
|
|
||||||
"version": "2.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/picocolors": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/picomatch": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/prettier": {
|
|
||||||
"version": "3.5.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
|
||||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"prettier": "bin/prettier.cjs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/prettier-plugin-organize-imports": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz",
|
|
||||||
"integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"peerDependencies": {
|
|
||||||
"prettier": ">=2.0",
|
|
||||||
"typescript": ">=2.9",
|
|
||||||
"vue-tsc": "^2.1.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"vue-tsc": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/prettier-plugin-packagejson": {
|
|
||||||
"version": "2.5.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.10.tgz",
|
|
||||||
"integrity": "sha512-LUxATI5YsImIVSaaLJlJ3aE6wTD+nvots18U3GuQMJpUyClChaZlQrqx3dBnbhF20OnKWZyx8EgyZypQtBDtgQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"sort-package-json": "2.15.1",
|
|
||||||
"synckit": "0.9.2"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"prettier": ">= 1.16.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"prettier": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/semver": {
|
|
||||||
"version": "7.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
|
||||||
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"bin": {
|
|
||||||
"semver": "bin/semver.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sort-object-keys": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.3.tgz",
|
|
||||||
"integrity": "sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/sort-package-json": {
|
|
||||||
"version": "2.15.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-2.15.1.tgz",
|
|
||||||
"integrity": "sha512-9x9+o8krTT2saA9liI4BljNjwAbvUnWf11Wq+i/iZt8nl2UGYnf3TH5uBydE7VALmP7AGwlfszuEeL8BDyb0YA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"detect-indent": "^7.0.1",
|
|
||||||
"detect-newline": "^4.0.0",
|
|
||||||
"get-stdin": "^9.0.0",
|
|
||||||
"git-hooks-list": "^3.0.0",
|
|
||||||
"is-plain-obj": "^4.1.0",
|
|
||||||
"semver": "^7.6.0",
|
|
||||||
"sort-object-keys": "^1.1.3",
|
|
||||||
"tinyglobby": "^0.2.9"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"sort-package-json": "cli.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/synckit": {
|
|
||||||
"version": "0.9.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz",
|
|
||||||
"integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@pkgr/core": "^0.1.0",
|
|
||||||
"tslib": "^2.6.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^14.18.0 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/unts"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tinyglobby": {
|
|
||||||
"version": "0.2.13",
|
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
|
|
||||||
"integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"fdir": "^6.4.4",
|
|
||||||
"picomatch": "^4.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tslib": {
|
|
||||||
"version": "2.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
|
||||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "0BSD"
|
|
||||||
},
|
|
||||||
"node_modules/typescript": {
|
|
||||||
"version": "5.8.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
|
||||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bin": {
|
|
||||||
"tsc": "bin/tsc",
|
|
||||||
"tsserver": "bin/tsserver"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.17"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
package.json
14
package.json
@ -1,15 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/authentik",
|
||||||
"version": "2025.4.1",
|
"version": "2025.4.0",
|
||||||
"private": true,
|
"private": true
|
||||||
"type": "module",
|
|
||||||
"devDependencies": {
|
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
|
||||||
"prettier": "^3.3.3",
|
|
||||||
"prettier-plugin-organize-imports": "^4.1.0",
|
|
||||||
"prettier-plugin-packagejson": "^2.5.10",
|
|
||||||
"typescript": "^5.6.2"
|
|
||||||
},
|
|
||||||
"workspaces": [],
|
|
||||||
"prettier": "./packages/prettier-config/index.js"
|
|
||||||
}
|
}
|
||||||
|
4
packages/docusaurus-config/package-lock.json
generated
4
packages/docusaurus-config/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/docusaurus-config",
|
"name": "@goauthentik/docusaurus-config",
|
||||||
"version": "1.0.6",
|
"version": "1.0.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@goauthentik/docusaurus-config",
|
"name": "@goauthentik/docusaurus-config",
|
||||||
"version": "1.0.6",
|
"version": "1.0.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"deepmerge-ts": "^7.1.5",
|
"deepmerge-ts": "^7.1.5",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/docusaurus-config",
|
"name": "@goauthentik/docusaurus-config",
|
||||||
"version": "1.0.6",
|
"version": "1.0.5",
|
||||||
"description": "authentik's Docusaurus config",
|
"description": "authentik's Docusaurus config",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
This package contains utility scripts common to all TypeScript and JavaScript packages in the
|
This package contains utility scripts common to all TypeScript and JavaScript packages in the
|
||||||
`@goauthentik` monorepo.
|
`@goauthentik` monorepo.
|
||||||
|
|
@ -1,9 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* @file Constants for JavaScript and TypeScript files.
|
* @file Constants for JavaScript and TypeScript files.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// <reference types="../../types/global.js" />
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current Node.js environment, defaulting to "development" when not set.
|
* The current Node.js environment, defaulting to "development" when not set.
|
||||||
*
|
*
|
||||||
@ -13,4 +12,6 @@
|
|||||||
* ensure that module tree-shaking works correctly.
|
* ensure that module tree-shaking works correctly.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const NodeEnvironment = process.env.NODE_ENV || "development";
|
export const NodeEnvironment = /** @type {'development' | 'production'} */ (
|
||||||
|
process.env.NODE_ENV || "development"
|
||||||
|
);
|
@ -1,7 +1,4 @@
|
|||||||
/// <reference types="./types/global.js" />
|
|
||||||
|
|
||||||
export * from "./paths.js";
|
export * from "./paths.js";
|
||||||
export * from "./constants.js";
|
export * from "./constants.js";
|
||||||
export * from "./build.js";
|
|
||||||
export * from "./version.js";
|
export * from "./version.js";
|
||||||
export * from "./scripting.js";
|
export * from "./scripting.js";
|
19
packages/monorepo/package.json
Normal file
19
packages/monorepo/package.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@goauthentik/monorepo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Utilities for the authentik monorepo.",
|
||||||
|
"private": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": {
|
||||||
|
"import": "./index.js",
|
||||||
|
"types": "./out/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"types": "./out/index.d.ts",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.11"
|
||||||
|
}
|
||||||
|
}
|
30
packages/monorepo/paths.js
Normal file
30
packages/monorepo/paths.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { createRequire } from "node:module";
|
||||||
|
import { dirname, join, resolve } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {'~authentik'} MonoRepoRoot
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The root of the authentik monorepo.
|
||||||
|
*/
|
||||||
|
export const MonoRepoRoot = /** @type {MonoRepoRoot} */ (resolve(__dirname, "..", ".."));
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a package name to its location in the monorepo to the single node_modules directory.
|
||||||
|
* @param {string} packageName
|
||||||
|
* @returns {string} The resolved path to the package.
|
||||||
|
* @throws {Error} If the package cannot be resolved.
|
||||||
|
*/
|
||||||
|
export function resolvePackage(packageName) {
|
||||||
|
const packageJSONPath = require.resolve(join(packageName, "package.json"), {
|
||||||
|
paths: [MonoRepoRoot],
|
||||||
|
});
|
||||||
|
|
||||||
|
return dirname(packageJSONPath);
|
||||||
|
}
|
0
packages/monorepo/scripts.js
Normal file
0
packages/monorepo/scripts.js
Normal file
@ -1,6 +1,6 @@
|
|||||||
import { execSync } from "node:child_process";
|
import { execSync } from "node:child_process";
|
||||||
|
|
||||||
import PackageJSON from "../../../package.json" with { type: "json" };
|
import PackageJSON from "../../package.json" with { type: "json" };
|
||||||
import { MonoRepoRoot } from "./paths.js";
|
import { MonoRepoRoot } from "./paths.js";
|
||||||
|
|
||||||
/**
|
/**
|
@ -76,7 +76,6 @@ EXPOSE 9000 9300 9443
|
|||||||
|
|
||||||
USER 1000
|
USER 1000
|
||||||
|
|
||||||
ENV TMPDIR=/dev/shm/ \
|
ENV GOFIPS=1
|
||||||
GOFIPS=1
|
|
||||||
|
|
||||||
ENTRYPOINT ["/proxy"]
|
ENTRYPOINT ["/proxy"]
|
||||||
|
200
pyproject.toml
200
pyproject.toml
@ -1,116 +1,104 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "authentik"
|
name = "authentik"
|
||||||
version = "2025.4.1"
|
version = "2025.4.0"
|
||||||
description = ""
|
description = ""
|
||||||
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
|
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
|
||||||
requires-python = "==3.13.*"
|
requires-python = "==3.12.*"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argon2-cffi==23.1.0",
|
"argon2-cffi",
|
||||||
"celery==5.5.2",
|
"celery",
|
||||||
"channels==4.2.2",
|
"channels",
|
||||||
"channels-redis==4.2.1",
|
"channels-redis",
|
||||||
"cryptography==44.0.3",
|
"cryptography",
|
||||||
"dacite==1.9.2",
|
"dacite",
|
||||||
"deepmerge==2.0",
|
"deepmerge",
|
||||||
"defusedxml==0.7.1",
|
"defusedxml",
|
||||||
"django==5.1.9",
|
"django",
|
||||||
"django-countries==7.6.1",
|
"django-countries",
|
||||||
"django-cte==1.3.3",
|
"django-cte",
|
||||||
"django-filter==25.1",
|
"django-filter",
|
||||||
"django-guardian<3.0.0",
|
"django-guardian",
|
||||||
"django-model-utils==5.0.0",
|
"django-model-utils",
|
||||||
"django-pglock==1.7.2",
|
"django-pglock",
|
||||||
"django-prometheus==2.3.1",
|
"django-prometheus",
|
||||||
"django-redis==5.4.0",
|
"django-redis",
|
||||||
"django-storages[s3]==1.14.6",
|
"django-storages[s3]",
|
||||||
"django-tenants==3.7.0",
|
"django-tenants",
|
||||||
"djangorestframework==3.16.0",
|
"djangorestframework",
|
||||||
"djangorestframework-guardian==0.3.0",
|
"djangorestframework-guardian",
|
||||||
"docker==7.1.0",
|
"docker",
|
||||||
"drf-orjson-renderer==1.7.3",
|
"drf-orjson-renderer",
|
||||||
"drf-spectacular==0.28.0",
|
"drf-spectacular",
|
||||||
"dumb-init==1.2.5.post1",
|
"dumb-init",
|
||||||
"duo-client==5.5.0",
|
"duo-client",
|
||||||
"fido2==1.2.0",
|
"fido2",
|
||||||
"flower==2.0.1",
|
"flower",
|
||||||
"geoip2==5.1.0",
|
"geoip2",
|
||||||
"geopy==2.4.1",
|
"geopy",
|
||||||
"google-api-python-client==2.169.0",
|
"google-api-python-client",
|
||||||
"gssapi==1.9.0",
|
"gssapi",
|
||||||
"gunicorn==23.0.0",
|
"gunicorn",
|
||||||
"jsonpatch==1.33",
|
"jsonpatch",
|
||||||
"jwcrypto==1.5.6",
|
"jwcrypto",
|
||||||
"kubernetes==32.0.1",
|
"kubernetes",
|
||||||
"ldap3==2.9.1",
|
"ldap3",
|
||||||
"lxml==5.4.0",
|
"lxml",
|
||||||
"msgraph-sdk==1.30.0",
|
"msgraph-sdk",
|
||||||
"opencontainers==0.0.14",
|
"opencontainers",
|
||||||
"packaging==25.0",
|
"packaging",
|
||||||
"paramiko==3.5.1",
|
"paramiko",
|
||||||
"psycopg[c,pool]==3.2.9",
|
"psycopg[c, pool]",
|
||||||
"pydantic==2.11.4",
|
"pydantic",
|
||||||
"pydantic-scim==0.0.8",
|
"pydantic-scim",
|
||||||
"pyjwt==2.10.1",
|
"pyjwt",
|
||||||
"pyrad==2.4",
|
"pyrad",
|
||||||
"python-kadmin-rs==0.6.0",
|
"python-kadmin-rs ==0.6.0",
|
||||||
"pyyaml==6.0.2",
|
"pyyaml",
|
||||||
"requests-oauthlib==2.0.0",
|
"requests-oauthlib",
|
||||||
"scim2-filter-parser==0.7.0",
|
"scim2-filter-parser",
|
||||||
"sentry-sdk==2.28.0",
|
"sentry-sdk",
|
||||||
"service-identity==24.2.0",
|
"service_identity",
|
||||||
"setproctitle==1.3.6",
|
"setproctitle",
|
||||||
"structlog==25.3.0",
|
"structlog",
|
||||||
"swagger-spec-validator==3.0.4",
|
"swagger-spec-validator",
|
||||||
"tenant-schemas-celery==4.0.1",
|
"tenant-schemas-celery",
|
||||||
"twilio==9.6.1",
|
"twilio",
|
||||||
"ua-parser==1.0.1",
|
"ua-parser",
|
||||||
"unidecode==1.4.0",
|
"unidecode",
|
||||||
"urllib3<3",
|
"urllib3 <3",
|
||||||
"uvicorn[standard]==0.34.2",
|
"uvicorn[standard]",
|
||||||
"watchdog==6.0.0",
|
"watchdog",
|
||||||
"webauthn==2.5.2",
|
"webauthn",
|
||||||
"wsproto==1.2.0",
|
"wsproto",
|
||||||
"xmlsec==1.3.15",
|
"xmlsec <= 1.3.14",
|
||||||
"zxcvbn==4.5.0",
|
"zxcvbn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
"aws-cdk-lib==2.188.0",
|
"aws-cdk-lib",
|
||||||
"bandit==1.8.3",
|
"bandit",
|
||||||
"black==25.1.0",
|
"black",
|
||||||
"bump2version==1.0.1",
|
"bump2version",
|
||||||
"channels[daphne]==4.2.2",
|
"channels[daphne]",
|
||||||
"codespell==2.4.1",
|
"codespell",
|
||||||
"colorama==0.4.6",
|
"colorama",
|
||||||
"constructs==10.4.2",
|
"constructs",
|
||||||
"coverage[toml]==7.8.0",
|
"coverage[toml]",
|
||||||
"debugpy==1.8.14",
|
"debugpy",
|
||||||
"drf-jsonschema-serializer==3.0.0",
|
"drf-jsonschema-serializer",
|
||||||
"freezegun==1.5.1",
|
"freezegun",
|
||||||
"importlib-metadata==8.6.1",
|
"importlib-metadata",
|
||||||
"k5test==0.10.4",
|
"k5test",
|
||||||
"pdoc==15.0.3",
|
"pdoc",
|
||||||
"pytest==8.3.5",
|
"pytest",
|
||||||
"pytest-django==4.11.1",
|
"pytest-django",
|
||||||
"pytest-github-actions-annotate-failures==0.3.0",
|
"pytest-github-actions-annotate-failures",
|
||||||
"pytest-randomly==3.16.0",
|
"pytest-randomly",
|
||||||
"pytest-timeout==2.4.0",
|
"pytest-timeout",
|
||||||
"requests-mock==1.12.1",
|
"requests-mock",
|
||||||
"ruff==0.11.9",
|
"ruff",
|
||||||
"selenium==4.32.0",
|
"selenium",
|
||||||
]
|
|
||||||
|
|
||||||
[tool.uv]
|
|
||||||
no-binary-package = [
|
|
||||||
# This differs from the no-binary packages in the Dockerfile. This is due to the fact
|
|
||||||
# that these packages are built from source for different reasons than cryptography and kadmin.
|
|
||||||
# These packages are built from source to link against the libxml2 on the system which is
|
|
||||||
# required for functionality and to stay up-to-date on both libraries.
|
|
||||||
# The other packages specified in the dockerfile are compiled from source to link against the
|
|
||||||
# correct FIPS OpenSSL libraries
|
|
||||||
"lxml",
|
|
||||||
"xmlsec",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
@ -155,12 +143,12 @@ ignore-words = ".github/codespell-words.txt"
|
|||||||
|
|
||||||
[tool.black]
|
[tool.black]
|
||||||
line-length = 100
|
line-length = 100
|
||||||
target-version = ['py313']
|
target-version = ['py312']
|
||||||
exclude = 'node_modules'
|
exclude = 'node_modules'
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 100
|
line-length = 100
|
||||||
target-version = "py313"
|
target-version = "py312"
|
||||||
exclude = ["**/migrations/**", "**/node_modules/**"]
|
exclude = ["**/migrations/**", "**/node_modules/**"]
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
|
@ -56,7 +56,6 @@ HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/rac", "healthch
|
|||||||
|
|
||||||
USER 1000
|
USER 1000
|
||||||
|
|
||||||
ENV TMPDIR=/dev/shm/ \
|
ENV GOFIPS=1
|
||||||
GOFIPS=1
|
|
||||||
|
|
||||||
ENTRYPOINT ["/rac"]
|
ENTRYPOINT ["/rac"]
|
||||||
|
@ -56,7 +56,6 @@ EXPOSE 1812/udp 9300
|
|||||||
|
|
||||||
USER 1000
|
USER 1000
|
||||||
|
|
||||||
ENV TMPDIR=/dev/shm/ \
|
ENV GOFIPS=1
|
||||||
GOFIPS=1
|
|
||||||
|
|
||||||
ENTRYPOINT ["/radius"]
|
ENTRYPOINT ["/radius"]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
openapi: 3.0.3
|
openapi: 3.0.3
|
||||||
info:
|
info:
|
||||||
title: authentik
|
title: authentik
|
||||||
version: 2025.4.1
|
version: 2025.4.0
|
||||||
description: Making authentication simple.
|
description: Making authentication simple.
|
||||||
contact:
|
contact:
|
||||||
email: hello@goauthentik.io
|
email: hello@goauthentik.io
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
services:
|
services:
|
||||||
chrome:
|
chrome:
|
||||||
image: docker.io/selenium/standalone-chrome:136.0
|
image: docker.io/selenium/standalone-chrome:122.0
|
||||||
volumes:
|
volumes:
|
||||||
- /dev/shm:/dev/shm
|
- /dev/shm:/dev/shm
|
||||||
network_mode: host
|
network_mode: host
|
||||||
restart: always
|
restart: always
|
||||||
mailpit:
|
mailpit:
|
||||||
image: docker.io/axllent/mailpit:v1.24.2
|
image: docker.io/axllent/mailpit:v1.6.5
|
||||||
ports:
|
ports:
|
||||||
- 1025:1025
|
- 1025:1025
|
||||||
- 8025:8025
|
- 8025:8025
|
||||||
|
@ -1,19 +1,12 @@
|
|||||||
"""test default login flow"""
|
"""test default login flow"""
|
||||||
|
|
||||||
from authentik.blueprints.tests import apply_blueprint
|
from authentik.blueprints.tests import apply_blueprint
|
||||||
from authentik.flows.models import Flow
|
|
||||||
from tests.e2e.utils import SeleniumTestCase, retry
|
from tests.e2e.utils import SeleniumTestCase, retry
|
||||||
|
|
||||||
|
|
||||||
class TestFlowsLogin(SeleniumTestCase):
|
class TestFlowsLogin(SeleniumTestCase):
|
||||||
"""test default login flow"""
|
"""test default login flow"""
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
# Reset authentication flow's compatibility mode; we need to do this as its
|
|
||||||
# not specified in the blueprint
|
|
||||||
Flow.objects.filter(slug="default-authentication-flow").update(compatibility_mode=False)
|
|
||||||
return super().tearDown()
|
|
||||||
|
|
||||||
@retry()
|
@retry()
|
||||||
@apply_blueprint(
|
@apply_blueprint(
|
||||||
"default/flow-default-authentication-flow.yaml",
|
"default/flow-default-authentication-flow.yaml",
|
||||||
@ -30,21 +23,3 @@ class TestFlowsLogin(SeleniumTestCase):
|
|||||||
self.login()
|
self.login()
|
||||||
self.wait_for_url(self.if_user_url("/library"))
|
self.wait_for_url(self.if_user_url("/library"))
|
||||||
self.assert_user(self.user)
|
self.assert_user(self.user)
|
||||||
|
|
||||||
@retry()
|
|
||||||
@apply_blueprint(
|
|
||||||
"default/flow-default-authentication-flow.yaml",
|
|
||||||
"default/flow-default-invalidation-flow.yaml",
|
|
||||||
)
|
|
||||||
def test_login_compatibility_mode(self):
|
|
||||||
"""test default login flow with compatibility mode enabled"""
|
|
||||||
Flow.objects.filter(slug="default-authentication-flow").update(compatibility_mode=True)
|
|
||||||
self.driver.get(
|
|
||||||
self.url(
|
|
||||||
"authentik_core:if-flow",
|
|
||||||
flow_slug="default-authentication-flow",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.login(shadow_dom=False)
|
|
||||||
self.wait_for_url(self.if_user_url("/library"))
|
|
||||||
self.assert_user(self.user)
|
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
"""test default login (using SFE interface) flow"""
|
|
||||||
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
from selenium.webdriver.common.by import By
|
|
||||||
from selenium.webdriver.common.keys import Keys
|
|
||||||
|
|
||||||
from authentik.blueprints.tests import apply_blueprint
|
|
||||||
from tests.e2e.utils import SeleniumTestCase, retry
|
|
||||||
|
|
||||||
|
|
||||||
class TestFlowsLoginSFE(SeleniumTestCase):
|
|
||||||
"""test default login flow"""
|
|
||||||
|
|
||||||
def login(self):
|
|
||||||
"""Do entire login flow adjusted for SFE"""
|
|
||||||
flow_executor = self.driver.find_element(By.ID, "flow-sfe-container")
|
|
||||||
identification_stage = flow_executor.find_element(By.ID, "ident-form")
|
|
||||||
|
|
||||||
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uid_field]").click()
|
|
||||||
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uid_field]").send_keys(
|
|
||||||
self.user.username
|
|
||||||
)
|
|
||||||
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uid_field]").send_keys(
|
|
||||||
Keys.ENTER
|
|
||||||
)
|
|
||||||
|
|
||||||
password_stage = flow_executor.find_element(By.ID, "password-form")
|
|
||||||
password_stage.find_element(By.CSS_SELECTOR, "input[name=password]").send_keys(
|
|
||||||
self.user.username
|
|
||||||
)
|
|
||||||
password_stage.find_element(By.CSS_SELECTOR, "input[name=password]").send_keys(Keys.ENTER)
|
|
||||||
sleep(1)
|
|
||||||
|
|
||||||
@retry()
|
|
||||||
@apply_blueprint(
|
|
||||||
"default/flow-default-authentication-flow.yaml",
|
|
||||||
"default/flow-default-invalidation-flow.yaml",
|
|
||||||
)
|
|
||||||
def test_login(self):
|
|
||||||
"""test default login flow"""
|
|
||||||
self.driver.get(
|
|
||||||
self.url(
|
|
||||||
"authentik_core:if-flow",
|
|
||||||
flow_slug="default-authentication-flow",
|
|
||||||
query={"sfe": True},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.login()
|
|
||||||
self.wait_for_url(self.if_user_url("/library"))
|
|
||||||
self.assert_user(self.user)
|
|
@ -26,10 +26,8 @@ from selenium import webdriver
|
|||||||
from selenium.common.exceptions import NoSuchElementException, TimeoutException, WebDriverException
|
from selenium.common.exceptions import NoSuchElementException, TimeoutException, WebDriverException
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
from selenium.webdriver.common.keys import Keys
|
from selenium.webdriver.common.keys import Keys
|
||||||
from selenium.webdriver.remote.command import Command
|
|
||||||
from selenium.webdriver.remote.webdriver import WebDriver
|
from selenium.webdriver.remote.webdriver import WebDriver
|
||||||
from selenium.webdriver.remote.webelement import WebElement
|
from selenium.webdriver.remote.webelement import WebElement
|
||||||
from selenium.webdriver.support import expected_conditions as ec
|
|
||||||
from selenium.webdriver.support.wait import WebDriverWait
|
from selenium.webdriver.support.wait import WebDriverWait
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
@ -38,8 +36,8 @@ from authentik.core.models import User
|
|||||||
from authentik.core.tests.utils import create_test_admin_user
|
from authentik.core.tests.utils import create_test_admin_user
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
|
|
||||||
|
RETRIES = int(environ.get("RETRIES", "3"))
|
||||||
IS_CI = "CI" in environ
|
IS_CI = "CI" in environ
|
||||||
RETRIES = int(environ.get("RETRIES", "3")) if IS_CI else 1
|
|
||||||
|
|
||||||
|
|
||||||
def get_docker_tag() -> str:
|
def get_docker_tag() -> str:
|
||||||
@ -199,12 +197,7 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
|
|||||||
super().tearDown()
|
super().tearDown()
|
||||||
if IS_CI:
|
if IS_CI:
|
||||||
print("::group::Browser logs")
|
print("::group::Browser logs")
|
||||||
# Very verbose way to get browser logs
|
for line in self.driver.get_log("browser"):
|
||||||
# https://github.com/SeleniumHQ/selenium/pull/15641
|
|
||||||
# for some reason this removes the `get_log` API from Remote Webdriver
|
|
||||||
# and only keeps it on the local Chrome web driver, even when using
|
|
||||||
# a remote chrome driver...? (nvm the fact this was released as a minor version)
|
|
||||||
for line in self.driver.execute(Command.GET_LOG, {"type": "browser"})["value"]:
|
|
||||||
print(line["message"])
|
print(line["message"])
|
||||||
if IS_CI:
|
if IS_CI:
|
||||||
print("::endgroup::")
|
print("::endgroup::")
|
||||||
@ -241,30 +234,10 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
|
|||||||
element = self.driver.execute_script("return arguments[0].shadowRoot", shadow_root)
|
element = self.driver.execute_script("return arguments[0].shadowRoot", shadow_root)
|
||||||
return element
|
return element
|
||||||
|
|
||||||
def shady_dom(self) -> WebElement:
|
def login(self):
|
||||||
class wrapper:
|
"""Do entire login flow and check user afterwards"""
|
||||||
def __init__(self, container: WebDriver):
|
flow_executor = self.get_shadow_root("ak-flow-executor")
|
||||||
self.container = container
|
identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
|
||||||
|
|
||||||
def find_element(self, by: str, selector: str) -> WebElement:
|
|
||||||
return self.container.execute_script(
|
|
||||||
"return document.__shady_native_querySelector(arguments[0])", selector
|
|
||||||
)
|
|
||||||
|
|
||||||
return wrapper(self.driver)
|
|
||||||
|
|
||||||
def login(self, shadow_dom=True):
|
|
||||||
"""Do entire login flow"""
|
|
||||||
|
|
||||||
if shadow_dom:
|
|
||||||
flow_executor = self.get_shadow_root("ak-flow-executor")
|
|
||||||
identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
|
|
||||||
else:
|
|
||||||
flow_executor = self.shady_dom()
|
|
||||||
identification_stage = self.shady_dom()
|
|
||||||
|
|
||||||
wait = WebDriverWait(identification_stage, self.wait_timeout)
|
|
||||||
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "input[name=uidField]")))
|
|
||||||
|
|
||||||
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uidField]").click()
|
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uidField]").click()
|
||||||
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uidField]").send_keys(
|
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uidField]").send_keys(
|
||||||
@ -274,16 +247,8 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
|
|||||||
Keys.ENTER
|
Keys.ENTER
|
||||||
)
|
)
|
||||||
|
|
||||||
if shadow_dom:
|
flow_executor = self.get_shadow_root("ak-flow-executor")
|
||||||
flow_executor = self.get_shadow_root("ak-flow-executor")
|
password_stage = self.get_shadow_root("ak-stage-password", flow_executor)
|
||||||
password_stage = self.get_shadow_root("ak-stage-password", flow_executor)
|
|
||||||
else:
|
|
||||||
flow_executor = self.shady_dom()
|
|
||||||
password_stage = self.shady_dom()
|
|
||||||
|
|
||||||
wait = WebDriverWait(password_stage, self.wait_timeout)
|
|
||||||
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "input[name=password]")))
|
|
||||||
|
|
||||||
password_stage.find_element(By.CSS_SELECTOR, "input[name=password]").send_keys(
|
password_stage.find_element(By.CSS_SELECTOR, "input[name=password]").send_keys(
|
||||||
self.user.username
|
self.user.username
|
||||||
)
|
)
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
// TypeScript Project Configuration
|
|
||||||
{
|
|
||||||
"extends": "./packages/tsconfig/tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"baseUrl": "."
|
|
||||||
},
|
|
||||||
"watchOptions": {
|
|
||||||
"excludeDirectories": [
|
|
||||||
"**/.git", // Git
|
|
||||||
"**/.yarn", // Yarn
|
|
||||||
"**/.vscode", // VS Code
|
|
||||||
"**/.vscode-test-web", // VS Code Web Test
|
|
||||||
"**/dist", // Distributed build files
|
|
||||||
"**/out", // Output build files
|
|
||||||
"**/.drafts", // Drafts
|
|
||||||
"**/.github", // GitHub
|
|
||||||
"**/node_modules" // Node modules
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
// The root project has no sources of its own. By setting `files` to an empty
|
|
||||||
// list, TS won't automatically include all sources below root (the default).
|
|
||||||
"files": [],
|
|
||||||
"references": [
|
|
||||||
// Note that references are in the order we want them to be built.
|
|
||||||
// TODO: Left blank until TypeScript workspaces are complete.
|
|
||||||
]
|
|
||||||
}
|
|
@ -2,11 +2,15 @@
|
|||||||
node_modules
|
node_modules
|
||||||
# don't lint build output (make sure it's set to your correct build folder name)
|
# don't lint build output (make sure it's set to your correct build folder name)
|
||||||
dist
|
dist
|
||||||
out
|
|
||||||
# don't lint nyc coverage output
|
# don't lint nyc coverage output
|
||||||
coverage
|
coverage
|
||||||
# Import order matters
|
# Import order matters
|
||||||
|
poly.ts
|
||||||
src/locale-codes.ts
|
src/locale-codes.ts
|
||||||
src/locales/
|
src/locales/
|
||||||
storybook-static/
|
storybook-static/
|
||||||
|
# Prettier breaks the tsconfig file
|
||||||
|
tsconfig.json
|
||||||
.storybook/css-import-maps*
|
.storybook/css-import-maps*
|
||||||
|
package.json
|
||||||
|
packages/**/package.json
|
||||||
|
11
web/.storybook/authentikTheme.ts
Normal file
11
web/.storybook/authentikTheme.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { create } from "@storybook/theming/create";
|
||||||
|
|
||||||
|
const isDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||||
|
|
||||||
|
export default create({
|
||||||
|
base: isDarkMode ? "dark" : "light",
|
||||||
|
brandTitle: "authentik Storybook",
|
||||||
|
brandUrl: "https://goauthentik.io",
|
||||||
|
brandImage: "https://goauthentik.io/img/icon_left_brand_colour.svg",
|
||||||
|
brandTarget: "_self",
|
||||||
|
});
|
@ -1,69 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Storybook configuration.
|
|
||||||
* @import { StorybookConfig } from "@storybook/web-components-vite";
|
|
||||||
* @import { InlineConfig, Plugin } from "vite";
|
|
||||||
*/
|
|
||||||
import { cwd } from "process";
|
|
||||||
import postcssLit from "rollup-plugin-postcss-lit";
|
|
||||||
import tsconfigPaths from "vite-tsconfig-paths";
|
|
||||||
|
|
||||||
const NODE_ENV = process.env.NODE_ENV || "development";
|
|
||||||
|
|
||||||
const CSSImportPattern = /import [\w\$]+ from .+\.(css)/g;
|
|
||||||
const JavaScriptFilePattern = /\.m?(js|ts|tsx)$/;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @satisfies {Plugin<never>}
|
|
||||||
*/
|
|
||||||
const inlineCSSPlugin = {
|
|
||||||
name: "inline-css-plugin",
|
|
||||||
transform: (source, id) => {
|
|
||||||
if (!JavaScriptFilePattern.test(id)) return;
|
|
||||||
|
|
||||||
const code = source.replace(CSSImportPattern, (match) => {
|
|
||||||
return `${match}?inline`;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
code,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @satisfies {StorybookConfig}
|
|
||||||
*/
|
|
||||||
const config = {
|
|
||||||
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
|
|
||||||
addons: [
|
|
||||||
"@storybook/addon-controls",
|
|
||||||
"@storybook/addon-links",
|
|
||||||
"@storybook/addon-essentials",
|
|
||||||
"storybook-addon-mock",
|
|
||||||
],
|
|
||||||
framework: {
|
|
||||||
name: "@storybook/web-components-vite",
|
|
||||||
options: {},
|
|
||||||
},
|
|
||||||
docs: {
|
|
||||||
autodocs: "tag",
|
|
||||||
},
|
|
||||||
viteFinal({ plugins = [], ...config }) {
|
|
||||||
/**
|
|
||||||
* @satisfies {InlineConfig}
|
|
||||||
*/
|
|
||||||
const mergedConfig = {
|
|
||||||
...config,
|
|
||||||
define: {
|
|
||||||
"process.env.NODE_ENV": JSON.stringify(NODE_ENV),
|
|
||||||
"process.env.CWD": JSON.stringify(cwd()),
|
|
||||||
"process.env.AK_API_BASE_PATH": JSON.stringify(process.env.AK_API_BASE_PATH || ""),
|
|
||||||
},
|
|
||||||
plugins: [inlineCSSPlugin, ...plugins, postcssLit(), tsconfigPaths()],
|
|
||||||
};
|
|
||||||
|
|
||||||
return mergedConfig;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default config;
|
|
81
web/.storybook/main.ts
Normal file
81
web/.storybook/main.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import replace from "@rollup/plugin-replace";
|
||||||
|
import type { StorybookConfig } from "@storybook/web-components-vite";
|
||||||
|
import { cwd } from "process";
|
||||||
|
import modify from "rollup-plugin-modify";
|
||||||
|
import postcssLit from "rollup-plugin-postcss-lit";
|
||||||
|
import tsconfigPaths from "vite-tsconfig-paths";
|
||||||
|
|
||||||
|
export const isProdBuild = process.env.NODE_ENV === "production";
|
||||||
|
export const apiBasePath = process.env.AK_API_BASE_PATH || "";
|
||||||
|
|
||||||
|
const importInlinePatterns = [
|
||||||
|
'import AKGlobal from "(\\.\\./)*common/styles/authentik\\.css',
|
||||||
|
'import AKGlobal from "@goauthentik/common/styles/authentik\\.css',
|
||||||
|
'import PF.+ from "@patternfly/patternfly/\\S+\\.css',
|
||||||
|
'import ThemeDark from "@goauthentik/common/styles/theme-dark\\.css',
|
||||||
|
'import OneDark from "@goauthentik/common/styles/one-dark\\.css',
|
||||||
|
'import styles from "\\./LibraryPageImpl\\.css',
|
||||||
|
];
|
||||||
|
|
||||||
|
const importInlineRegexp = new RegExp(importInlinePatterns.map((a) => `(${a})`).join("|"));
|
||||||
|
|
||||||
|
const config: StorybookConfig = {
|
||||||
|
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
|
||||||
|
addons: [
|
||||||
|
"@storybook/addon-controls",
|
||||||
|
"@storybook/addon-links",
|
||||||
|
"@storybook/addon-essentials",
|
||||||
|
"storybook-addon-mock",
|
||||||
|
],
|
||||||
|
staticDirs: [
|
||||||
|
{
|
||||||
|
from: "../node_modules/@patternfly/patternfly/patternfly-base.css",
|
||||||
|
to: "@patternfly/patternfly/patternfly-base.css",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "../src/common/styles/authentik.css",
|
||||||
|
to: "@goauthentik/common/styles/authentik.css",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "../src/common/styles/theme-dark.css",
|
||||||
|
to: "@goauthentik/common/styles/theme-dark.css",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "../src/common/styles/one-dark.css",
|
||||||
|
to: "@goauthentik/common/styles/one-dark.css",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
framework: {
|
||||||
|
name: "@storybook/web-components-vite",
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
autodocs: "tag",
|
||||||
|
},
|
||||||
|
async viteFinal(config) {
|
||||||
|
return {
|
||||||
|
...config,
|
||||||
|
plugins: [
|
||||||
|
modify({
|
||||||
|
find: importInlineRegexp,
|
||||||
|
replace: (match: RegExpMatchArray) => {
|
||||||
|
return `${match}?inline`;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
replace({
|
||||||
|
"process.env.NODE_ENV": JSON.stringify(
|
||||||
|
isProdBuild ? "production" : "development",
|
||||||
|
),
|
||||||
|
"process.env.CWD": JSON.stringify(cwd()),
|
||||||
|
"process.env.AK_API_BASE_PATH": JSON.stringify(apiBasePath),
|
||||||
|
"preventAssignment": true,
|
||||||
|
}),
|
||||||
|
...config.plugins,
|
||||||
|
postcssLit(),
|
||||||
|
tsconfigPaths(),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
@ -1,38 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Storybook manager configuration.
|
|
||||||
*
|
|
||||||
* @import { ThemeVarsPartial } from "storybook/internal/theming";
|
|
||||||
*/
|
|
||||||
import { createUIThemeEffect, resolveUITheme } from "@goauthentik/web/common/theme.ts";
|
|
||||||
import { addons } from "@storybook/manager-api";
|
|
||||||
import { create } from "@storybook/theming/create";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @satisfies {Partial<ThemeVarsPartial>}
|
|
||||||
*/
|
|
||||||
const baseTheme = {
|
|
||||||
brandTitle: "authentik Storybook",
|
|
||||||
brandUrl: "https://goauthentik.io",
|
|
||||||
brandImage: "https://goauthentik.io/img/icon_left_brand_colour.svg",
|
|
||||||
brandTarget: "_self",
|
|
||||||
};
|
|
||||||
|
|
||||||
const uiTheme = resolveUITheme();
|
|
||||||
|
|
||||||
addons.setConfig({
|
|
||||||
theme: create({
|
|
||||||
...baseTheme,
|
|
||||||
base: uiTheme,
|
|
||||||
}),
|
|
||||||
enableShortcuts: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
createUIThemeEffect((nextUITheme) => {
|
|
||||||
addons.setConfig({
|
|
||||||
theme: create({
|
|
||||||
...baseTheme,
|
|
||||||
base: nextUITheme,
|
|
||||||
}),
|
|
||||||
enableShortcuts: false,
|
|
||||||
});
|
|
||||||
});
|
|
9
web/.storybook/manager.ts
Normal file
9
web/.storybook/manager.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// .storybook/manager.js
|
||||||
|
import { addons } from "@storybook/manager-api";
|
||||||
|
|
||||||
|
import authentikTheme from "./authentikTheme";
|
||||||
|
|
||||||
|
addons.setConfig({
|
||||||
|
theme: authentikTheme,
|
||||||
|
enableShortcuts: false,
|
||||||
|
});
|
@ -1,3 +1,5 @@
|
|||||||
|
<link rel="stylesheet" href="@patternfly/patternfly/patternfly-base.css" />
|
||||||
|
<link rel="stylesheet" href="@goauthentik/common/styles/authentik.css" />
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
/// <reference types="../types/css.js" />
|
|
||||||
/**
|
|
||||||
* @file Storybook manager configuration.
|
|
||||||
*
|
|
||||||
* @import { Preview } from "@storybook/web-components";
|
|
||||||
*/
|
|
||||||
import { applyDocumentTheme } from "@goauthentik/web/common/theme.ts";
|
|
||||||
|
|
||||||
applyDocumentTheme();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @satisfies {Preview}
|
|
||||||
*/
|
|
||||||
const preview = {
|
|
||||||
parameters: {
|
|
||||||
options: {
|
|
||||||
storySort: {
|
|
||||||
method: "alphabetical",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
|
||||||
|
|
||||||
controls: {
|
|
||||||
matchers: {
|
|
||||||
color: /(background|color)$/i,
|
|
||||||
date: /Date$/,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default preview;
|
|
30
web/.storybook/preview.ts
Normal file
30
web/.storybook/preview.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import type { Preview } from "@storybook/web-components";
|
||||||
|
|
||||||
|
import "@goauthentik/common/styles/authentik.css";
|
||||||
|
// import "@goauthentik/common/styles/theme-dark.css";
|
||||||
|
import "@patternfly/patternfly/components/Brand/brand.css";
|
||||||
|
import "@patternfly/patternfly/components/Page/page.css";
|
||||||
|
// .storybook/preview.js
|
||||||
|
import "@patternfly/patternfly/patternfly-base.css";
|
||||||
|
|
||||||
|
const preview: Preview = {
|
||||||
|
parameters: {
|
||||||
|
options: {
|
||||||
|
storySort: {
|
||||||
|
method: "alphabetical",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||||
|
cssUserPrefs: {
|
||||||
|
"prefers-color-scheme": "light",
|
||||||
|
},
|
||||||
|
controls: {
|
||||||
|
matchers: {
|
||||||
|
color: /(background|color)$/i,
|
||||||
|
date: /Date$/,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default preview;
|
3529
web/package-lock.json
generated
3529
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
140
web/package.json
140
web/package.json
@ -1,50 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/web",
|
"name": "@goauthentik/web",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "MIT",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"build": "wireit",
|
|
||||||
"build-locales": "wireit",
|
|
||||||
"build-locales:build": "wireit",
|
|
||||||
"build-proxy": "wireit",
|
|
||||||
"build:sfe": "wireit",
|
|
||||||
"esbuild:watch": "node scripts/build-web.mjs --watch",
|
|
||||||
"extract-locales": "wireit",
|
|
||||||
"format": "wireit",
|
|
||||||
"lint": "wireit",
|
|
||||||
"lint:imports": "wireit",
|
|
||||||
"lint:lockfile": "wireit",
|
|
||||||
"lint:nightmare": "wireit",
|
|
||||||
"lint:precommit": "wireit",
|
|
||||||
"lint:types": "wireit",
|
|
||||||
"lit-analyse": "wireit",
|
|
||||||
"precommit": "wireit",
|
|
||||||
"prettier": "wireit",
|
|
||||||
"prettier-check": "wireit",
|
|
||||||
"pseudolocalize": "wireit",
|
|
||||||
"storybook": "storybook dev -p 6006",
|
|
||||||
"storybook:build": "wireit",
|
|
||||||
"test": "wireit",
|
|
||||||
"test:e2e": "wireit",
|
|
||||||
"test:e2e:watch": "wireit",
|
|
||||||
"test:watch": "wireit",
|
|
||||||
"tsc": "wireit",
|
|
||||||
"watch": "run-s build-locales esbuild:watch"
|
|
||||||
},
|
|
||||||
"type": "module",
|
|
||||||
"exports": {
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./paths": "./paths.js",
|
|
||||||
"./scripts/*": "./scripts/*.mjs",
|
|
||||||
"./elements/*": "./src/elements/*",
|
|
||||||
"./common/*": "./src/common/*",
|
|
||||||
"./components/*": "./src/components/*",
|
|
||||||
"./flow/*": "./src/flow/*",
|
|
||||||
"./locales/*": "./src/locales/*",
|
|
||||||
"./user/*": "./src/user/*",
|
|
||||||
"./admin/*": "./src/admin/*"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
"@codemirror/lang-html": "^6.4.9",
|
"@codemirror/lang-html": "^6.4.9",
|
||||||
@ -56,7 +12,8 @@
|
|||||||
"@floating-ui/dom": "^1.6.11",
|
"@floating-ui/dom": "^1.6.11",
|
||||||
"@formatjs/intl-listformat": "^7.5.7",
|
"@formatjs/intl-listformat": "^7.5.7",
|
||||||
"@fortawesome/fontawesome-free": "^6.6.0",
|
"@fortawesome/fontawesome-free": "^6.6.0",
|
||||||
"@goauthentik/api": "^2025.4.1-1747332783",
|
"@goauthentik/api": "^2025.4.0-1746018955",
|
||||||
|
"@lit-labs/ssr": "3.2.2",
|
||||||
"@lit/context": "^1.1.2",
|
"@lit/context": "^1.1.2",
|
||||||
"@lit/localize": "^0.12.2",
|
"@lit/localize": "^0.12.2",
|
||||||
"@lit/reactive-element": "^2.0.4",
|
"@lit/reactive-element": "^2.0.4",
|
||||||
@ -97,7 +54,6 @@
|
|||||||
"remark-gfm": "^4.0.1",
|
"remark-gfm": "^4.0.1",
|
||||||
"remark-mdx-frontmatter": "^5.0.0",
|
"remark-mdx-frontmatter": "^5.0.0",
|
||||||
"style-mod": "^4.1.2",
|
"style-mod": "^4.1.2",
|
||||||
"trusted-types": "^2.0.0",
|
|
||||||
"ts-pattern": "^5.4.0",
|
"ts-pattern": "^5.4.0",
|
||||||
"unist-util-visit": "^5.0.0",
|
"unist-util-visit": "^5.0.0",
|
||||||
"webcomponent-qr-code": "^1.2.0",
|
"webcomponent-qr-code": "^1.2.0",
|
||||||
@ -106,20 +62,19 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.11.1",
|
"@eslint/js": "^9.11.1",
|
||||||
"@goauthentik/esbuild-plugin-live-reload": "^1.0.4",
|
"@goauthentik/esbuild-plugin-live-reload": "^1.0.4",
|
||||||
"@goauthentik/monorepo": "^1.0.0",
|
|
||||||
"@goauthentik/prettier-config": "^1.0.4",
|
"@goauthentik/prettier-config": "^1.0.4",
|
||||||
"@goauthentik/tsconfig": "^1.0.4",
|
"@goauthentik/tsconfig": "^1.0.4",
|
||||||
"@hcaptcha/types": "^1.0.4",
|
"@hcaptcha/types": "^1.0.4",
|
||||||
"@lit/localize-tools": "^0.8.0",
|
"@lit/localize-tools": "^0.8.0",
|
||||||
"@rollup/plugin-replace": "^6.0.1",
|
"@rollup/plugin-replace": "^6.0.1",
|
||||||
"@storybook/addon-essentials": "^8.6.12",
|
"@storybook/addon-essentials": "^8.3.4",
|
||||||
"@storybook/addon-links": "^8.6.12",
|
"@storybook/addon-links": "^8.3.4",
|
||||||
"@storybook/blocks": "^8.6.12",
|
"@storybook/api": "^7.6.17",
|
||||||
"@storybook/experimental-addon-test": "^8.6.12",
|
"@storybook/blocks": "^8.3.4",
|
||||||
"@storybook/manager-api": "^8.6.12",
|
"@storybook/builder-vite": "^8.3.4",
|
||||||
"@storybook/test": "^8.6.12",
|
"@storybook/manager-api": "^8.3.4",
|
||||||
"@storybook/web-components": "^8.6.12",
|
"@storybook/web-components": "^8.3.4",
|
||||||
"@storybook/web-components-vite": "^8.6.12",
|
"@storybook/web-components-vite": "^8.3.4",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||||
"@types/chart.js": "^2.9.41",
|
"@types/chart.js": "^2.9.41",
|
||||||
"@types/codemirror": "^5.60.15",
|
"@types/codemirror": "^5.60.15",
|
||||||
@ -138,22 +93,24 @@
|
|||||||
"@wdio/spec-reporter": "^9.1.2",
|
"@wdio/spec-reporter": "^9.1.2",
|
||||||
"chromedriver": "^131.0.1",
|
"chromedriver": "^131.0.1",
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"esbuild-plugin-copy": "^2.1.1",
|
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
"esbuild-plugins-node-modules-polyfill": "^1.7.0",
|
"esbuild-plugins-node-modules-polyfill": "^1.7.0",
|
||||||
"eslint": "^9.11.1",
|
"eslint": "^9.11.1",
|
||||||
"eslint-plugin-lit": "^1.15.0",
|
"eslint-plugin-lit": "^1.15.0",
|
||||||
"eslint-plugin-wc": "^2.1.1",
|
"eslint-plugin-wc": "^2.1.1",
|
||||||
"github-slugger": "^2.0.0",
|
"github-slugger": "^2.0.0",
|
||||||
|
"glob": "^11.0.0",
|
||||||
"globals": "^15.10.0",
|
"globals": "^15.10.0",
|
||||||
"knip": "^5.30.6",
|
"knip": "^5.30.6",
|
||||||
"lit-analyzer": "^2.0.3",
|
"lit-analyzer": "^2.0.3",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"pseudolocale": "^2.1.0",
|
"pseudolocale": "^2.1.0",
|
||||||
|
"rollup-plugin-modify": "^3.0.0",
|
||||||
"rollup-plugin-postcss-lit": "^2.1.0",
|
"rollup-plugin-postcss-lit": "^2.1.0",
|
||||||
"storybook": "^8.6.12",
|
"storybook": "^8.3.4",
|
||||||
"storybook-addon-mock": "^5.0.0",
|
"storybook-addon-mock": "^5.0.0",
|
||||||
|
"syncpack": "^13.0.0",
|
||||||
"turnstile-types": "^1.2.3",
|
"turnstile-types": "^1.2.3",
|
||||||
"typescript": "^5.6.2",
|
"typescript": "^5.6.2",
|
||||||
"typescript-eslint": "^8.8.0",
|
"typescript-eslint": "^8.8.0",
|
||||||
@ -161,6 +118,10 @@
|
|||||||
"vite-tsconfig-paths": "^5.0.1",
|
"vite-tsconfig-paths": "^5.0.1",
|
||||||
"wireit": "^0.14.9"
|
"wireit": "^0.14.9"
|
||||||
},
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/darwin-arm64": "^0.24.0",
|
"@esbuild/darwin-arm64": "^0.24.0",
|
||||||
"@esbuild/linux-amd64": "^0.18.11",
|
"@esbuild/linux-amd64": "^0.18.11",
|
||||||
@ -169,6 +130,48 @@
|
|||||||
"@rollup/rollup-linux-arm64-gnu": "4.23.0",
|
"@rollup/rollup-linux-arm64-gnu": "4.23.0",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.23.0"
|
"@rollup/rollup-linux-x64-gnu": "4.23.0"
|
||||||
},
|
},
|
||||||
|
"overrides": {
|
||||||
|
"rapidoc": {
|
||||||
|
"@apitools/openapi-parser@": "0.0.37"
|
||||||
|
},
|
||||||
|
"chromedriver": {
|
||||||
|
"axios": "^1.8.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prettier": "@goauthentik/prettier-config",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "wireit",
|
||||||
|
"build-locales": "wireit",
|
||||||
|
"build-locales:build": "wireit",
|
||||||
|
"build-proxy": "wireit",
|
||||||
|
"build:sfe": "wireit",
|
||||||
|
"esbuild:watch": "node scripts/build-web.mjs --watch",
|
||||||
|
"extract-locales": "wireit",
|
||||||
|
"format": "wireit",
|
||||||
|
"lint": "wireit",
|
||||||
|
"lint:imports": "wireit",
|
||||||
|
"lint:lockfile": "wireit",
|
||||||
|
"lint:nightmare": "wireit",
|
||||||
|
"lint:package": "wireit",
|
||||||
|
"lint:precommit": "wireit",
|
||||||
|
"lint:types": "wireit",
|
||||||
|
"lit-analyse": "wireit",
|
||||||
|
"postinstall": "bash scripts/patch-spotlight.sh",
|
||||||
|
"precommit": "wireit",
|
||||||
|
"prettier": "wireit",
|
||||||
|
"prettier-check": "wireit",
|
||||||
|
"pseudolocalize": "wireit",
|
||||||
|
"storybook": "storybook dev -p 6006",
|
||||||
|
"storybook:build": "wireit",
|
||||||
|
"test": "wireit",
|
||||||
|
"test:e2e": "wireit",
|
||||||
|
"test:e2e:watch": "wireit",
|
||||||
|
"test:watch": "wireit",
|
||||||
|
"tsc": "wireit",
|
||||||
|
"watch": "run-s build-locales esbuild:watch"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
"wireit": {
|
"wireit": {
|
||||||
"build": {
|
"build": {
|
||||||
"#comment": [
|
"#comment": [
|
||||||
@ -245,7 +248,10 @@
|
|||||||
"command": "lit-localize extract"
|
"command": "lit-localize extract"
|
||||||
},
|
},
|
||||||
"format": {
|
"format": {
|
||||||
"command": "prettier --write ."
|
"command": "prettier --write .",
|
||||||
|
"dependencies": [
|
||||||
|
"lint:package"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"format:packages": {
|
"format:packages": {
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
@ -284,6 +290,9 @@
|
|||||||
"./packages/sfe:lint:lockfile"
|
"./packages/sfe:lint:lockfile"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"lint:package": {
|
||||||
|
"command": "syncpack format -i ' '"
|
||||||
|
},
|
||||||
"lint:nightmare": {
|
"lint:nightmare": {
|
||||||
"command": "${NODE_RUNNER} ./scripts/eslint.mjs --nightmare",
|
"command": "${NODE_RUNNER} ./scripts/eslint.mjs --nightmare",
|
||||||
"env": {
|
"env": {
|
||||||
@ -314,6 +323,7 @@
|
|||||||
"lint:types",
|
"lint:types",
|
||||||
"lint:components",
|
"lint:components",
|
||||||
"lint:spelling",
|
"lint:spelling",
|
||||||
|
"lint:package",
|
||||||
"lint:lockfile",
|
"lint:lockfile",
|
||||||
"lint:lockfiles",
|
"lint:lockfiles",
|
||||||
"lint:precommit",
|
"lint:precommit",
|
||||||
@ -378,20 +388,8 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"engines": {
|
|
||||||
"node": ">=20"
|
|
||||||
},
|
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
".",
|
".",
|
||||||
"./packages/*"
|
"./packages/*"
|
||||||
],
|
]
|
||||||
"prettier": "@goauthentik/prettier-config",
|
|
||||||
"overrides": {
|
|
||||||
"rapidoc": {
|
|
||||||
"@apitools/openapi-parser@": "0.0.37"
|
|
||||||
},
|
|
||||||
"chromedriver": {
|
|
||||||
"axios": "^1.8.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* @import { Message as ESBuildMessage } from "esbuild";
|
* @import { Message as ESBuildMessage } from "esbuild";
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const logPrefix = "authentik/dev/web: ";
|
const logPrefix = "👷 [ESBuild]";
|
||||||
const log = console.debug.bind(console, logPrefix);
|
const log = console.debug.bind(console, logPrefix);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,7 +76,7 @@ export class ESBuildObserver extends EventSource {
|
|||||||
*/
|
*/
|
||||||
#startListener = () => {
|
#startListener = () => {
|
||||||
this.#trackActivity();
|
this.#trackActivity();
|
||||||
log("⏰ Build started...");
|
log("⏰ Build started...");
|
||||||
};
|
};
|
||||||
|
|
||||||
#internalErrorListener = () => {
|
#internalErrorListener = () => {
|
||||||
@ -86,7 +86,7 @@ export class ESBuildObserver extends EventSource {
|
|||||||
clearTimeout(this.#keepAliveInterval);
|
clearTimeout(this.#keepAliveInterval);
|
||||||
|
|
||||||
this.close();
|
this.close();
|
||||||
log("⛔️ Closing connection");
|
log("⛔️ Closing connection");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -126,13 +126,13 @@ export class ESBuildObserver extends EventSource {
|
|||||||
this.#trackActivity();
|
this.#trackActivity();
|
||||||
|
|
||||||
if (!this.online) {
|
if (!this.online) {
|
||||||
log("🚫 Build finished while offline.");
|
log("🚫 Build finished while offline.");
|
||||||
this.deferredReload = true;
|
this.deferredReload = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log("🛎️ Build completed! Reloading...");
|
log("🛎️ Build completed! Reloading...");
|
||||||
|
|
||||||
// We use an animation frame to keep the reload from happening before the
|
// We use an animation frame to keep the reload from happening before the
|
||||||
// event loop has a chance to process the message.
|
// event loop has a chance to process the message.
|
||||||
@ -189,13 +189,13 @@ export class ESBuildObserver extends EventSource {
|
|||||||
|
|
||||||
if (!this.deferredReload) return;
|
if (!this.deferredReload) return;
|
||||||
|
|
||||||
log("🛎️ Reloading after offline build...");
|
log("🛎️ Reloading after offline build...");
|
||||||
this.deferredReload = false;
|
this.deferredReload = false;
|
||||||
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
log("🛎️ Listening for build changes...");
|
log("🛎️ Listening for build changes...");
|
||||||
|
|
||||||
this.#keepAliveInterval = setInterval(() => {
|
this.#keepAliveInterval = setInterval(() => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
@ -203,7 +203,7 @@ export class ESBuildObserver extends EventSource {
|
|||||||
if (now - this.lastUpdatedAt < 10_000) return;
|
if (now - this.lastUpdatedAt < 10_000) return;
|
||||||
|
|
||||||
this.alive = false;
|
this.alive = false;
|
||||||
log("👋 Waiting for build to start...");
|
log("👋 Waiting for build to start...");
|
||||||
}, 15_000);
|
}, 15_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/esbuild-plugin-live-reload",
|
"name": "@goauthentik/esbuild-plugin-live-reload",
|
||||||
"version": "1.0.4",
|
|
||||||
"description": "ESBuild plugin to watch for file changes and trigger client-side reloads.",
|
"description": "ESBuild plugin to watch for file changes and trigger client-side reloads.",
|
||||||
"license": "MIT",
|
"version": "1.0.4",
|
||||||
"private": true,
|
"dependencies": {
|
||||||
"main": "index.js",
|
"find-free-ports": "^3.1.1"
|
||||||
"type": "module",
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@goauthentik/prettier-config": "^1.0.4",
|
||||||
|
"@goauthentik/tsconfig": "^1.0.4",
|
||||||
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||||
|
"@types/node": "^22.14.1",
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
|
"prettier": "^3.3.3",
|
||||||
|
"typescript": "^5.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.11"
|
||||||
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"./package.json": "./package.json",
|
"./package.json": "./package.json",
|
||||||
".": {
|
".": {
|
||||||
@ -21,33 +32,22 @@
|
|||||||
"import": "./plugin/index.js"
|
"import": "./plugin/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
|
||||||
"find-free-ports": "^3.1.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@goauthentik/prettier-config": "^1.0.4",
|
|
||||||
"@goauthentik/tsconfig": "^1.0.4",
|
|
||||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
|
||||||
"@types/node": "^22.14.1",
|
|
||||||
"esbuild": "^0.25.0",
|
|
||||||
"prettier": "^3.3.3",
|
|
||||||
"typescript": "^5.6.2"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"esbuild": "^0.25.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.11"
|
|
||||||
},
|
|
||||||
"types": "./out/index.d.ts",
|
|
||||||
"files": [
|
"files": [
|
||||||
"./index.js",
|
"./index.js",
|
||||||
"client/**/*",
|
"client/**/*",
|
||||||
"plugin/**/*",
|
"plugin/**/*",
|
||||||
"out/**/*"
|
"out/**/*"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "index.js",
|
||||||
|
"peerDependencies": {
|
||||||
|
"esbuild": "^0.25.0"
|
||||||
|
},
|
||||||
"prettier": "@goauthentik/prettier-config",
|
"prettier": "@goauthentik/prettier-config",
|
||||||
|
"private": true,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
}
|
},
|
||||||
|
"type": "module",
|
||||||
|
"types": "./out/index.d.ts"
|
||||||
}
|
}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Utility functions for building and copying files.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A source environment variable, which can be a string, number, boolean, null, or undefined.
|
|
||||||
* @typedef {string | number | boolean | null | undefined} EnvironmentVariable
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A type helper for serializing environment variables.
|
|
||||||
*
|
|
||||||
* @template {EnvironmentVariable} T
|
|
||||||
* @typedef {T extends string ? `"${T}"` : T} JSONify
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an object of environment variables, returns a new object with the same keys and values, but
|
|
||||||
* with the values serialized as strings.
|
|
||||||
*
|
|
||||||
* @template {Record<string, EnvironmentVariable>} EnvRecord
|
|
||||||
* @template {string} [Prefix='process.env.']
|
|
||||||
*
|
|
||||||
* @param {EnvRecord} input
|
|
||||||
* @param {Prefix} [prefix='process.env.']
|
|
||||||
*
|
|
||||||
* @returns {{[K in keyof EnvRecord as `${Prefix}${K}`]: JSONify<EnvRecord[K]>}}
|
|
||||||
*/
|
|
||||||
export function serializeEnvironmentVars(input, prefix = /** @type {Prefix} */ ("process.env.")) {
|
|
||||||
/**
|
|
||||||
* @type {Record<string, string>}
|
|
||||||
*/
|
|
||||||
const env = {};
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(input)) {
|
|
||||||
const namespaceKey = prefix + key;
|
|
||||||
|
|
||||||
env[namespaceKey] = JSON.stringify(value || "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return /** @type {any} */ (env);
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@goauthentik/monorepo",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Utilities for the authentik monorepo.",
|
|
||||||
"license": "MIT",
|
|
||||||
"private": true,
|
|
||||||
"main": "index.js",
|
|
||||||
"type": "module",
|
|
||||||
"exports": {
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
".": {
|
|
||||||
"types": "./out/index.d.ts",
|
|
||||||
"import": "./index.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@goauthentik/prettier-config": "^1.0.4",
|
|
||||||
"@goauthentik/tsconfig": "^1.0.4",
|
|
||||||
"@types/node": "^22.14.1",
|
|
||||||
"prettier": "^3.3.3",
|
|
||||||
"typescript": "^5.6.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.11"
|
|
||||||
},
|
|
||||||
"types": "./out/index.d.ts",
|
|
||||||
"prettier": "@goauthentik/prettier-config"
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
import { createRequire } from "node:module";
|
|
||||||
import { dirname, join, resolve } from "node:path";
|
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
|
|
||||||
const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {'~authentik'} MonoRepoRoot
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The root of the authentik monorepo.
|
|
||||||
*/
|
|
||||||
// TODO: Revise when this package is moved to the monorepo's `packages/monorepo` directory.
|
|
||||||
export const MonoRepoRoot = /** @type {MonoRepoRoot} */ (
|
|
||||||
resolve(relativeDirname, "..", "..", "..")
|
|
||||||
);
|
|
||||||
|
|
||||||
const require = createRequire(import.meta.url);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a package name to its location in the monorepo to the single node_modules directory.
|
|
||||||
* @param {string} packageName
|
|
||||||
*
|
|
||||||
* @returns {string} The resolved path to the package.
|
|
||||||
* @throws {Error} If the package cannot be resolved.
|
|
||||||
*/
|
|
||||||
export function resolvePackage(packageName) {
|
|
||||||
const relativePackageJSONPath = join(packageName, "package.json");
|
|
||||||
|
|
||||||
/** @type {string} */
|
|
||||||
let absolutePackageJSONPath;
|
|
||||||
|
|
||||||
try {
|
|
||||||
absolutePackageJSONPath = require.resolve(relativePackageJSONPath);
|
|
||||||
} catch (cause) {
|
|
||||||
const error = new Error(`Failed to resolve package "${packageName}"`);
|
|
||||||
|
|
||||||
error.cause = cause;
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dirname(absolutePackageJSONPath);
|
|
||||||
}
|
|
15
web/packages/monorepo/types/global.d.ts
vendored
15
web/packages/monorepo/types/global.d.ts
vendored
@ -1,15 +0,0 @@
|
|||||||
declare module "process" {
|
|
||||||
global {
|
|
||||||
namespace NodeJS {
|
|
||||||
interface ProcessEnv {
|
|
||||||
/**
|
|
||||||
* An environment variable used to determine
|
|
||||||
* whether Node.js is running in production mode.
|
|
||||||
*
|
|
||||||
* @see {@link https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production | The difference between development and production}
|
|
||||||
*/
|
|
||||||
NODE_ENV?: "production" | "development";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -47,16 +47,7 @@ class SimpleFlowExecutor {
|
|||||||
return `${ak().api.base}api/v3/flows/executor/${this.flowSlug}/?query=${encodeURIComponent(window.location.search.substring(1))}`;
|
return `${ak().api.base}api/v3/flows/executor/${this.flowSlug}/?query=${encodeURIComponent(window.location.search.substring(1))}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
loading() {
|
|
||||||
this.container.innerHTML = `<div class="d-flex justify-content-center">
|
|
||||||
<div class="spinner-border spinner-border-md" role="status">
|
|
||||||
<span class="sr-only">Loading...</span>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
this.loading();
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "GET",
|
type: "GET",
|
||||||
url: this.apiURL,
|
url: this.apiURL,
|
||||||
@ -210,9 +201,6 @@ class PasswordStage extends Stage<PasswordChallenge> {
|
|||||||
<form id="password-form">
|
<form id="password-form">
|
||||||
<img class="mb-4 brand-icon" src="${ak().brand.branding_logo}" alt="">
|
<img class="mb-4 brand-icon" src="${ak().brand.branding_logo}" alt="">
|
||||||
<h1 class="h3 mb-3 fw-normal text-center">${this.challenge?.flowInfo?.title}</h1>
|
<h1 class="h3 mb-3 fw-normal text-center">${this.challenge?.flowInfo?.title}</h1>
|
||||||
<div class="form-label-group my-3">
|
|
||||||
<input type="text" readonly class="form-control-plaintext" value="Welcome, ${this.challenge?.pendingUser}.">
|
|
||||||
</div>
|
|
||||||
<div class="form-label-group my-3 has-validation">
|
<div class="form-label-group my-3 has-validation">
|
||||||
<input type="password" autofocus class="form-control ${this.error("password").length > 0 ? IS_INVALID : ""}" name="password" placeholder="Password">
|
<input type="password" autofocus class="form-control ${this.error("password").length > 0 ? IS_INVALID : ""}" name="password" placeholder="Password">
|
||||||
${this.renderInputError("password")}
|
${this.renderInputError("password")}
|
||||||
|
78
web/paths.js
78
web/paths.js
@ -1,78 +0,0 @@
|
|||||||
import { dirname, resolve } from "node:path";
|
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
|
|
||||||
const relativeDirname = dirname(fileURLToPath(import.meta.url));
|
|
||||||
|
|
||||||
//#region Base paths
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {'@goauthentik/web'} WebPackageIdentifier
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The root of the web package.
|
|
||||||
*/
|
|
||||||
export const PackageRoot = /** @type {WebPackageIdentifier} */ (resolve(relativeDirname));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the distribution directory.
|
|
||||||
*/
|
|
||||||
export const DistDirectoryName = "dist";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Path to the web package's distribution directory.
|
|
||||||
*
|
|
||||||
* This is where the built files are located after running the build process.
|
|
||||||
*/
|
|
||||||
export const DistDirectory = /** @type {`${WebPackageIdentifier}/${DistDirectoryName}`} */ (
|
|
||||||
resolve(relativeDirname, DistDirectoryName)
|
|
||||||
);
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region Entry points
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{ in: string, out: string }} EntryPointTarget
|
|
||||||
*
|
|
||||||
* ESBuild entrypoint target.
|
|
||||||
* Matches the type defined in the ESBuild context.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Entry points available for building.
|
|
||||||
*
|
|
||||||
* @satisfies {Record<string, EntryPointTarget>}
|
|
||||||
*/
|
|
||||||
export const EntryPoint = /** @type {const} */ ({
|
|
||||||
Admin: {
|
|
||||||
in: resolve(PackageRoot, "src", "admin", "AdminInterface", "index.entrypoint.ts"),
|
|
||||||
out: resolve(DistDirectory, "admin", "AdminInterface"),
|
|
||||||
},
|
|
||||||
User: {
|
|
||||||
in: resolve(PackageRoot, "src", "user", "index.entrypoint.ts"),
|
|
||||||
out: resolve(DistDirectory, "user", "UserInterface"),
|
|
||||||
},
|
|
||||||
Flow: {
|
|
||||||
in: resolve(PackageRoot, "src", "flow", "index.entrypoint.ts"),
|
|
||||||
out: resolve(DistDirectory, "flow", "FlowInterface"),
|
|
||||||
},
|
|
||||||
Standalone: {
|
|
||||||
in: resolve(PackageRoot, "src", "standalone", "api-browser/index.entrypoint.ts"),
|
|
||||||
out: resolve(DistDirectory, "standalone", "api-browser", "index"),
|
|
||||||
},
|
|
||||||
StandaloneLoading: {
|
|
||||||
in: resolve(PackageRoot, "src", "standalone", "loading/index.entrypoint.ts"),
|
|
||||||
out: resolve(DistDirectory, "standalone", "loading", "index"),
|
|
||||||
},
|
|
||||||
RAC: {
|
|
||||||
in: resolve(PackageRoot, "src", "rac", "index.entrypoint.ts"),
|
|
||||||
out: resolve(DistDirectory, "rac", "index"),
|
|
||||||
},
|
|
||||||
Polyfill: {
|
|
||||||
in: resolve(PackageRoot, "src", "polyfill", "index.entrypoint.ts"),
|
|
||||||
out: resolve(DistDirectory, "poly"),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
//#endregion
|
|
@ -4,86 +4,138 @@
|
|||||||
* @import { BuildOptions } from "esbuild";
|
* @import { BuildOptions } from "esbuild";
|
||||||
*/
|
*/
|
||||||
import { liveReloadPlugin } from "@goauthentik/esbuild-plugin-live-reload/plugin";
|
import { liveReloadPlugin } from "@goauthentik/esbuild-plugin-live-reload/plugin";
|
||||||
import {
|
import { execFileSync } from "child_process";
|
||||||
MonoRepoRoot,
|
|
||||||
NodeEnvironment,
|
|
||||||
readBuildIdentifier,
|
|
||||||
resolvePackage,
|
|
||||||
serializeEnvironmentVars,
|
|
||||||
} from "@goauthentik/monorepo";
|
|
||||||
import { DistDirectory, DistDirectoryName, EntryPoint, PackageRoot } from "@goauthentik/web/paths";
|
|
||||||
import { deepmerge } from "deepmerge-ts";
|
import { deepmerge } from "deepmerge-ts";
|
||||||
import esbuild from "esbuild";
|
import esbuild from "esbuild";
|
||||||
import copy from "esbuild-plugin-copy";
|
|
||||||
import { polyfillNode } from "esbuild-plugin-polyfill-node";
|
import { polyfillNode } from "esbuild-plugin-polyfill-node";
|
||||||
import * as fs from "node:fs/promises";
|
import { copyFileSync, mkdirSync, readFileSync, statSync } from "fs";
|
||||||
import * as path from "node:path";
|
import { globSync } from "glob";
|
||||||
|
import * as path from "path";
|
||||||
|
import { cwd } from "process";
|
||||||
|
import process from "process";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
import { mdxPlugin } from "./esbuild/build-mdx-plugin.mjs";
|
import { mdxPlugin } from "./esbuild/build-mdx-plugin.mjs";
|
||||||
|
|
||||||
const logPrefix = "[Build]";
|
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
||||||
|
let authentikProjectRoot = path.join(__dirname, "..", "..");
|
||||||
|
|
||||||
const definitions = serializeEnvironmentVars({
|
try {
|
||||||
NODE_ENV: NodeEnvironment,
|
// Use the package.json file in the root folder, as it has the current version information.
|
||||||
CWD: process.cwd(),
|
authentikProjectRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
||||||
AK_API_BASE_PATH: process.env.AK_API_BASE_PATH,
|
encoding: "utf8",
|
||||||
});
|
}).replace("\n", "");
|
||||||
|
} catch (_error) {
|
||||||
|
// We probably don't have a .git folder, which could happen in container builds.
|
||||||
|
}
|
||||||
|
|
||||||
const patternflyPath = resolvePackage("@patternfly/patternfly");
|
const packageJSONPath = path.join(authentikProjectRoot, "./package.json");
|
||||||
|
const rootPackage = JSON.parse(readFileSync(packageJSONPath, "utf8"));
|
||||||
|
|
||||||
|
const NODE_ENV = process.env.NODE_ENV || "development";
|
||||||
|
const AK_API_BASE_PATH = process.env.AK_API_BASE_PATH || "";
|
||||||
|
|
||||||
|
const environmentVars = new Map([
|
||||||
|
["NODE_ENV", NODE_ENV],
|
||||||
|
["CWD", cwd()],
|
||||||
|
["AK_API_BASE_PATH", AK_API_BASE_PATH],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const definitions = Object.fromEntries(
|
||||||
|
Array.from(environmentVars).map(([key, value]) => {
|
||||||
|
return [`process.env.${key}`, JSON.stringify(value)];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Readonly<BuildOptions>}
|
* All is magic is just to make sure the assets are copied into the right places. This is a very
|
||||||
|
* stripped down version of what the rollup-copy-plugin does, without any of the features we don't
|
||||||
|
* use, and using globSync instead of globby since we already had globSync lying around thanks to
|
||||||
|
* Typescript. If there's a third argument in an array entry, it's used to replace the internal path
|
||||||
|
* before concatenating it all together as the destination target.
|
||||||
|
* @type {Array<[string, string, string?]>}
|
||||||
|
*/
|
||||||
|
const assetsFileMappings = [
|
||||||
|
["node_modules/@patternfly/patternfly/patternfly.min.css", "."],
|
||||||
|
["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"],
|
||||||
|
["src/common/styles/**", "."],
|
||||||
|
["src/assets/images/**", "./assets/images"],
|
||||||
|
["./icons/*", "./assets/icons"],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} filePath
|
||||||
|
*/
|
||||||
|
const isFile = (filePath) => statSync(filePath).isFile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} src Source file
|
||||||
|
* @param {string} dest Destination folder
|
||||||
|
* @param {string} [strip] Path to strip from the source file
|
||||||
|
*/
|
||||||
|
function nameCopyTarget(src, dest, strip) {
|
||||||
|
const target = path.join(dest, strip ? src.replace(strip, "") : path.parse(src).base);
|
||||||
|
return [src, target];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [source, rawdest, strip] of assetsFileMappings) {
|
||||||
|
const matchedPaths = globSync(source);
|
||||||
|
const dest = path.join("dist", rawdest);
|
||||||
|
|
||||||
|
const copyTargets = matchedPaths.map((path) => nameCopyTarget(path, dest, strip));
|
||||||
|
|
||||||
|
for (const [src, dest] of copyTargets) {
|
||||||
|
if (isFile(src)) {
|
||||||
|
mkdirSync(path.dirname(dest), { recursive: true });
|
||||||
|
copyFileSync(src, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {[source: string, destination: string]} EntryPoint
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This starts the definitions used for esbuild: Our targets, our arguments, the function for
|
||||||
|
* running a build, and three options for building: watching, building, and building the proxy.
|
||||||
|
* Ordered by largest to smallest interface to build even faster
|
||||||
|
*
|
||||||
|
* @type {EntryPoint[]}
|
||||||
|
*/
|
||||||
|
const entryPoints = [
|
||||||
|
["admin/AdminInterface/AdminInterface.ts", "admin"],
|
||||||
|
["user/UserInterface.ts", "user"],
|
||||||
|
["flow/FlowInterface.ts", "flow"],
|
||||||
|
["standalone/api-browser/index.ts", "standalone/api-browser"],
|
||||||
|
["rac/index.ts", "rac"],
|
||||||
|
["standalone/loading/index.ts", "standalone/loading"],
|
||||||
|
["polyfill/poly.ts", "."],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("esbuild").BuildOptions}
|
||||||
*/
|
*/
|
||||||
const BASE_ESBUILD_OPTIONS = {
|
const BASE_ESBUILD_OPTIONS = {
|
||||||
entryNames: `[dir]/[name]-${readBuildIdentifier()}`,
|
|
||||||
chunkNames: "[dir]/chunks/[name]-[hash]",
|
|
||||||
assetNames: "assets/[dir]/[name]-[hash]",
|
|
||||||
publicPath: path.join("/static", DistDirectoryName),
|
|
||||||
outdir: DistDirectory,
|
|
||||||
bundle: true,
|
bundle: true,
|
||||||
write: true,
|
write: true,
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
minify: NodeEnvironment === "production",
|
minify: NODE_ENV === "production",
|
||||||
legalComments: "external",
|
|
||||||
splitting: true,
|
splitting: true,
|
||||||
treeShaking: true,
|
treeShaking: true,
|
||||||
external: ["*.woff", "*.woff2"],
|
external: ["*.woff", "*.woff2"],
|
||||||
tsconfig: path.resolve(PackageRoot, "tsconfig.build.json"),
|
tsconfig: path.resolve(__dirname, "..", "tsconfig.build.json"),
|
||||||
loader: {
|
loader: {
|
||||||
".css": "text",
|
".css": "text",
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
copy({
|
|
||||||
assets: [
|
|
||||||
{
|
|
||||||
from: path.join(patternflyPath, "patternfly.min.css"),
|
|
||||||
to: ".",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: path.join(patternflyPath, "assets", "**"),
|
|
||||||
to: "./assets",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: path.resolve(PackageRoot, "src", "common", "styles", "**"),
|
|
||||||
to: ".",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: path.resolve(PackageRoot, "src", "assets", "images", "**"),
|
|
||||||
to: "./assets/images",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: path.resolve(PackageRoot, "icons", "*"),
|
|
||||||
to: "./assets/icons",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
polyfillNode({
|
polyfillNode({
|
||||||
polyfills: {
|
polyfills: {
|
||||||
path: true,
|
path: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
mdxPlugin({
|
mdxPlugin({
|
||||||
root: MonoRepoRoot,
|
root: authentikProjectRoot,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
define: definitions,
|
define: definitions,
|
||||||
@ -99,43 +151,69 @@ const BASE_ESBUILD_OPTIONS = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
async function cleanDistDirectory() {
|
/**
|
||||||
const timerLabel = `${logPrefix} ♻️ Cleaning previous builds...`;
|
* Creates a version ID for the build.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function composeVersionID() {
|
||||||
|
const { version } = rootPackage;
|
||||||
|
const buildHash = process.env.GIT_BUILD_HASH;
|
||||||
|
|
||||||
console.time(timerLabel);
|
if (buildHash) {
|
||||||
|
return `${version}+${buildHash}`;
|
||||||
|
}
|
||||||
|
|
||||||
await fs.rm(DistDirectory, {
|
return version;
|
||||||
recursive: true,
|
|
||||||
force: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
await fs.mkdir(DistDirectory, {
|
|
||||||
recursive: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.timeEnd(timerLabel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an ESBuild options, extending the base options with the given overrides.
|
* Build a single entry point.
|
||||||
*
|
*
|
||||||
* @param {BuildOptions} overrides
|
* @param {EntryPoint} buildTarget
|
||||||
* @returns {BuildOptions}
|
* @param {Partial<esbuild.BuildOptions>} [overrides]
|
||||||
|
* @throws {Error} on build failure
|
||||||
*/
|
*/
|
||||||
export function createESBuildOptions(overrides) {
|
function createEntryPointOptions([source, dest], overrides = {}) {
|
||||||
/**
|
const outdir = path.join(__dirname, "..", "dist", dest);
|
||||||
* @type {BuildOptions}
|
|
||||||
*/
|
|
||||||
const mergedOptions = deepmerge(BASE_ESBUILD_OPTIONS, overrides);
|
|
||||||
|
|
||||||
return mergedOptions;
|
/**
|
||||||
|
* @type {esbuild.BuildOptions}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const entryPointConfig = {
|
||||||
|
entryPoints: [`./src/${source}`],
|
||||||
|
entryNames: `[dir]/[name]-${composeVersionID()}`,
|
||||||
|
publicPath: path.join("/static", "dist", dest),
|
||||||
|
outdir,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {esbuild.BuildOptions}
|
||||||
|
*/
|
||||||
|
const mergedConfig = deepmerge(BASE_ESBUILD_OPTIONS, entryPointConfig, overrides);
|
||||||
|
|
||||||
|
return mergedConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build all entry points in parallel.
|
||||||
|
*
|
||||||
|
* @param {EntryPoint[]} entryPoints
|
||||||
|
* @returns {Promise<esbuild.BuildResult[]>}
|
||||||
|
*/
|
||||||
|
async function buildParallel(entryPoints) {
|
||||||
|
return Promise.all(
|
||||||
|
entryPoints.map((entryPoint) => {
|
||||||
|
return esbuild.build(createEntryPointOptions(entryPoint));
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function doHelp() {
|
function doHelp() {
|
||||||
console.log(`Build the authentik UI
|
console.log(`Build the authentik UI
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-w, --watch: Build all interfaces
|
-w, --watch: Build all ${entryPoints.length} interfaces
|
||||||
-p, --proxy: Build only the polyfills and the loading application
|
-p, --proxy: Build only the polyfills and the loading application
|
||||||
-h, --help: This help message
|
-h, --help: This help message
|
||||||
`);
|
`);
|
||||||
@ -144,29 +222,27 @@ function doHelp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function doWatch() {
|
async function doWatch() {
|
||||||
console.group(`${logPrefix} 🤖 Watching entry points`);
|
console.log("Watching all entry points...");
|
||||||
|
|
||||||
const entryPoints = Object.entries(EntryPoint).map(([entrypointID, target]) => {
|
const buildContexts = await Promise.all(
|
||||||
console.log(entrypointID);
|
entryPoints.map((entryPoint) => {
|
||||||
|
return esbuild.context(
|
||||||
|
createEntryPointOptions(entryPoint, {
|
||||||
|
define: definitions,
|
||||||
|
plugins: [
|
||||||
|
liveReloadPlugin({
|
||||||
|
logPrefix: `Build Observer (${entryPoint[1]})`,
|
||||||
|
relativeRoot: path.join(__dirname, ".."),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
return target;
|
await Promise.all(buildContexts.map((context) => context.rebuild()));
|
||||||
});
|
|
||||||
|
|
||||||
console.groupEnd();
|
await Promise.allSettled(buildContexts.map((context) => context.watch()));
|
||||||
|
|
||||||
const buildOptions = createESBuildOptions({
|
|
||||||
entryPoints,
|
|
||||||
plugins: [
|
|
||||||
liveReloadPlugin({
|
|
||||||
relativeRoot: PackageRoot,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const buildContext = await esbuild.context(buildOptions);
|
|
||||||
|
|
||||||
await buildContext.rebuild();
|
|
||||||
await buildContext.watch();
|
|
||||||
|
|
||||||
return /** @type {Promise<void>} */ (
|
return /** @type {Promise<void>} */ (
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
@ -178,34 +254,15 @@ async function doWatch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function doBuild() {
|
async function doBuild() {
|
||||||
console.group(`${logPrefix} 🚀 Building entry points:`);
|
console.log("Building all entry points");
|
||||||
|
|
||||||
const entryPoints = Object.entries(EntryPoint).map(([entrypointID, target]) => {
|
return buildParallel(entryPoints);
|
||||||
console.log(entrypointID);
|
|
||||||
|
|
||||||
return target;
|
|
||||||
});
|
|
||||||
|
|
||||||
console.groupEnd();
|
|
||||||
|
|
||||||
const buildOptions = createESBuildOptions({
|
|
||||||
entryPoints,
|
|
||||||
});
|
|
||||||
|
|
||||||
await esbuild.build(buildOptions);
|
|
||||||
|
|
||||||
console.log("Build complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doProxy() {
|
async function doProxy() {
|
||||||
const entryPoints = [EntryPoint.StandaloneLoading];
|
return buildParallel(
|
||||||
|
entryPoints.filter(([_, dest]) => ["standalone/loading", "."].includes(dest)),
|
||||||
const buildOptions = createESBuildOptions({
|
);
|
||||||
entryPoints,
|
|
||||||
});
|
|
||||||
|
|
||||||
await esbuild.build(buildOptions);
|
|
||||||
console.log("Proxy build complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function delegateCommand() {
|
async function delegateCommand() {
|
||||||
@ -227,16 +284,12 @@ async function delegateCommand() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await cleanDistDirectory()
|
await delegateCommand()
|
||||||
// ---
|
.then(() => {
|
||||||
.then(() =>
|
console.log("Build complete");
|
||||||
delegateCommand()
|
process.exit(0);
|
||||||
.then(() => {
|
})
|
||||||
console.log("Build complete");
|
.catch((error) => {
|
||||||
process.exit(0);
|
console.error(error);
|
||||||
})
|
process.exit(1);
|
||||||
.catch((error) => {
|
});
|
||||||
console.error(error);
|
|
||||||
process.exit(1);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
33
web/scripts/patch-spotlight.sh
Normal file
33
web/scripts/patch-spotlight.sh
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
TARGET="./node_modules/@spotlightjs/overlay/dist/index-"[0-9a-f]*.js
|
||||||
|
|
||||||
|
if [[ $(grep -L "QX2" "$TARGET" > /dev/null 2> /dev/null) ]]; then
|
||||||
|
patch --forward -V none --no-backup-if-mismatch -p0 $TARGET <<EOF
|
||||||
|
|
||||||
|
TARGET=$(find "./node_modules/@spotlightjs/overlay/dist/" -name "index-[0-9a-f]*.js");
|
||||||
|
|
||||||
|
if ! grep -GL 'QX2 = ' "$TARGET" > /dev/null ; then
|
||||||
|
patch --forward --no-backup-if-mismatch -p0 "$TARGET" <<EOF
|
||||||
|
>>>>>>> main
|
||||||
|
--- a/index-5682ce90.js 2024-06-13 16:19:28
|
||||||
|
+++ b/index-5682ce90.js 2024-06-13 16:20:23
|
||||||
|
@@ -4958,11 +4958,10 @@
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
-const q2 = w.lazy(() => import("./main-3257b7fc.js").then((n) => n.m));
|
||||||
|
+const q2 = w.lazy(() => import("./main-3257b7fc.js").then((n) => n.m)), QX2 = () => {};
|
||||||
|
function Gp({
|
||||||
|
data: n,
|
||||||
|
- onUpdateData: a = () => {
|
||||||
|
- },
|
||||||
|
+ onUpdateData: a = QX2,
|
||||||
|
editingEnabled: s = !1,
|
||||||
|
clipboardEnabled: o = !1,
|
||||||
|
displayDataTypes: c = !1,
|
||||||
|
EOF
|
||||||
|
|
||||||
|
else
|
||||||
|
echo "spotlight overlay.js patch already applied"
|
||||||
|
fi
|
@ -1,11 +1,11 @@
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { VERSION } from "@goauthentik/common/constants";
|
import { VERSION } from "@goauthentik/common/constants";
|
||||||
import { globalAK } from "@goauthentik/common/global";
|
import { globalAK } from "@goauthentik/common/global";
|
||||||
import { DefaultBrand } from "@goauthentik/common/ui/config";
|
|
||||||
import "@goauthentik/elements/EmptyState";
|
import "@goauthentik/elements/EmptyState";
|
||||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||||
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider";
|
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider";
|
||||||
import { ModalButton } from "@goauthentik/elements/buttons/ModalButton";
|
import { ModalButton } from "@goauthentik/elements/buttons/ModalButton";
|
||||||
|
import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { TemplateResult, css, html } from "lit";
|
import { TemplateResult, css, html } from "lit";
|
||||||
|
@ -9,12 +9,8 @@ import { configureSentry } from "@goauthentik/common/sentry";
|
|||||||
import { me } from "@goauthentik/common/users";
|
import { me } from "@goauthentik/common/users";
|
||||||
import { WebsocketClient } from "@goauthentik/common/ws";
|
import { WebsocketClient } from "@goauthentik/common/ws";
|
||||||
import { AuthenticatedInterface } from "@goauthentik/elements/Interface";
|
import { AuthenticatedInterface } from "@goauthentik/elements/Interface";
|
||||||
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider.js";
|
|
||||||
import { SidebarToggleEventDetail } from "@goauthentik/elements/PageHeader";
|
|
||||||
import "@goauthentik/elements/ak-locale-context";
|
import "@goauthentik/elements/ak-locale-context";
|
||||||
import "@goauthentik/elements/banner/EnterpriseStatusBanner";
|
import "@goauthentik/elements/banner/EnterpriseStatusBanner";
|
||||||
import "@goauthentik/elements/banner/EnterpriseStatusBanner";
|
|
||||||
import "@goauthentik/elements/banner/VersionBanner";
|
|
||||||
import "@goauthentik/elements/banner/VersionBanner";
|
import "@goauthentik/elements/banner/VersionBanner";
|
||||||
import "@goauthentik/elements/messages/MessageContainer";
|
import "@goauthentik/elements/messages/MessageContainer";
|
||||||
import "@goauthentik/elements/messages/MessageContainer";
|
import "@goauthentik/elements/messages/MessageContainer";
|
||||||
@ -25,124 +21,79 @@ import "@goauthentik/elements/router/RouterOutlet";
|
|||||||
import "@goauthentik/elements/sidebar/Sidebar";
|
import "@goauthentik/elements/sidebar/Sidebar";
|
||||||
import "@goauthentik/elements/sidebar/SidebarItem";
|
import "@goauthentik/elements/sidebar/SidebarItem";
|
||||||
|
|
||||||
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
|
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||||
import { customElement, eventOptions, property, query } from "lit/decorators.js";
|
import { customElement, property, query, state } from "lit/decorators.js";
|
||||||
import { classMap } from "lit/directives/class-map.js";
|
import { classMap } from "lit/directives/class-map.js";
|
||||||
|
|
||||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||||
import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css";
|
import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css";
|
||||||
import PFNav from "@patternfly/patternfly/components/Nav/nav.css";
|
|
||||||
import PFPage from "@patternfly/patternfly/components/Page/page.css";
|
import PFPage from "@patternfly/patternfly/components/Page/page.css";
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
|
|
||||||
import { LicenseSummaryStatusEnum, SessionUser, UiThemeEnum } from "@goauthentik/api";
|
import { SessionUser, UiThemeEnum } from "@goauthentik/api";
|
||||||
|
|
||||||
import {
|
import "./AdminSidebar";
|
||||||
AdminSidebarEnterpriseEntries,
|
|
||||||
AdminSidebarEntries,
|
|
||||||
renderSidebarItems,
|
|
||||||
} from "./AdminSidebar.js";
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === "development") {
|
||||||
await import("@goauthentik/esbuild-plugin-live-reload/client");
|
await import("@goauthentik/esbuild-plugin-live-reload/client");
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("ak-interface-admin")
|
@customElement("ak-interface-admin")
|
||||||
export class AdminInterface extends WithLicenseSummary(AuthenticatedInterface) {
|
export class AdminInterface extends AuthenticatedInterface {
|
||||||
//#region Properties
|
@property({ type: Boolean })
|
||||||
|
notificationDrawerOpen = getURLParam("notificationDrawerOpen", false);
|
||||||
|
|
||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
public notificationDrawerOpen = getURLParam("notificationDrawerOpen", false);
|
apiDrawerOpen = getURLParam("apiDrawerOpen", false);
|
||||||
|
|
||||||
@property({ type: Boolean })
|
ws: WebsocketClient;
|
||||||
public apiDrawerOpen = getURLParam("apiDrawerOpen", false);
|
|
||||||
|
|
||||||
protected readonly ws: WebsocketClient;
|
@state()
|
||||||
|
user?: SessionUser;
|
||||||
@property({
|
|
||||||
type: Object,
|
|
||||||
attribute: false,
|
|
||||||
reflect: false,
|
|
||||||
})
|
|
||||||
public user?: SessionUser;
|
|
||||||
|
|
||||||
@query("ak-about-modal")
|
@query("ak-about-modal")
|
||||||
public aboutModal?: AboutModal;
|
aboutModal?: AboutModal;
|
||||||
|
|
||||||
@property({ type: Boolean, reflect: true })
|
static get styles(): CSSResult[] {
|
||||||
public sidebarOpen: boolean;
|
return [
|
||||||
|
PFBase,
|
||||||
@eventOptions({ passive: true })
|
PFPage,
|
||||||
protected sidebarListener(event: CustomEvent<SidebarToggleEventDetail>) {
|
PFButton,
|
||||||
this.sidebarOpen = !!event.detail.open;
|
PFDrawer,
|
||||||
}
|
css`
|
||||||
|
.pf-c-page__main,
|
||||||
#sidebarMatcher: MediaQueryList;
|
.pf-c-drawer__content,
|
||||||
#sidebarMediaQueryListener = (event: MediaQueryListEvent) => {
|
.pf-c-page__drawer {
|
||||||
this.sidebarOpen = event.matches;
|
z-index: auto !important;
|
||||||
};
|
background-color: transparent;
|
||||||
|
}
|
||||||
//#endregion
|
.display-none {
|
||||||
|
display: none;
|
||||||
//#region Styles
|
}
|
||||||
|
|
||||||
static styles: CSSResult[] = [
|
|
||||||
PFBase,
|
|
||||||
PFPage,
|
|
||||||
PFButton,
|
|
||||||
PFDrawer,
|
|
||||||
PFNav,
|
|
||||||
css`
|
|
||||||
.pf-c-page__main,
|
|
||||||
.pf-c-drawer__content,
|
|
||||||
.pf-c-page__drawer {
|
|
||||||
z-index: auto !important;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.display-none {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pf-c-page {
|
|
||||||
background-color: var(--pf-c-page--BackgroundColor) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([theme="dark"]) {
|
|
||||||
/* Global page background colour */
|
|
||||||
.pf-c-page {
|
.pf-c-page {
|
||||||
|
background-color: var(--pf-c-page--BackgroundColor) !important;
|
||||||
|
}
|
||||||
|
/* Global page background colour */
|
||||||
|
:host([theme="dark"]) .pf-c-page {
|
||||||
--pf-c-page--BackgroundColor: var(--ak-dark-background);
|
--pf-c-page--BackgroundColor: var(--ak-dark-background);
|
||||||
}
|
}
|
||||||
}
|
ak-enterprise-status,
|
||||||
|
ak-version-banner {
|
||||||
ak-page-navbar {
|
grid-area: header;
|
||||||
grid-area: header;
|
}
|
||||||
}
|
ak-admin-sidebar {
|
||||||
|
grid-area: nav;
|
||||||
.ak-sidebar {
|
}
|
||||||
grid-area: nav;
|
.pf-c-drawer__panel {
|
||||||
}
|
z-index: var(--pf-global--ZIndex--xl);
|
||||||
|
}
|
||||||
.pf-c-drawer__panel {
|
`,
|
||||||
z-index: var(--pf-global--ZIndex--xl);
|
];
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region Lifecycle
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
configureSentry(true);
|
|
||||||
super();
|
|
||||||
this.ws = new WebsocketClient();
|
|
||||||
this.#sidebarMatcher = window.matchMedia("(min-width: 1200px)");
|
|
||||||
this.sidebarOpen = this.#sidebarMatcher.matches;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public connectedCallback() {
|
constructor() {
|
||||||
super.connectedCallback();
|
super();
|
||||||
|
this.ws = new WebsocketClient();
|
||||||
|
|
||||||
window.addEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, () => {
|
window.addEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, () => {
|
||||||
this.notificationDrawerOpen = !this.notificationDrawerOpen;
|
this.notificationDrawerOpen = !this.notificationDrawerOpen;
|
||||||
@ -157,25 +108,16 @@ export class AdminInterface extends WithLicenseSummary(AuthenticatedInterface) {
|
|||||||
apiDrawerOpen: this.apiDrawerOpen,
|
apiDrawerOpen: this.apiDrawerOpen,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#sidebarMatcher.addEventListener("change", this.#sidebarMediaQueryListener, {
|
|
||||||
passive: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public disconnectedCallback(): void {
|
|
||||||
super.disconnectedCallback();
|
|
||||||
this.#sidebarMatcher.removeEventListener("change", this.#sidebarMediaQueryListener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async firstUpdated(): Promise<void> {
|
async firstUpdated(): Promise<void> {
|
||||||
|
configureSentry(true);
|
||||||
this.user = await me();
|
this.user = await me();
|
||||||
|
|
||||||
const canAccessAdmin =
|
const canAccessAdmin =
|
||||||
this.user.user.isSuperuser ||
|
this.user.user.isSuperuser ||
|
||||||
// TODO: somehow add `access_admin_interface` to the API schema
|
// TODO: somehow add `access_admin_interface` to the API schema
|
||||||
this.user.user.systemPermissions.includes("access_admin_interface");
|
this.user.user.systemPermissions.includes("access_admin_interface");
|
||||||
|
|
||||||
if (!canAccessAdmin && this.user.user.pk > 0) {
|
if (!canAccessAdmin && this.user.user.pk > 0) {
|
||||||
window.location.assign("/if/user/");
|
window.location.assign("/if/user/");
|
||||||
}
|
}
|
||||||
@ -183,14 +125,10 @@ export class AdminInterface extends WithLicenseSummary(AuthenticatedInterface) {
|
|||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
const sidebarClasses = {
|
const sidebarClasses = {
|
||||||
"pf-c-page__sidebar": true,
|
|
||||||
"pf-m-light": this.activeTheme === UiThemeEnum.Light,
|
"pf-m-light": this.activeTheme === UiThemeEnum.Light,
|
||||||
"pf-m-expanded": this.sidebarOpen,
|
|
||||||
"pf-m-collapsed": !this.sidebarOpen,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const drawerOpen = this.notificationDrawerOpen || this.apiDrawerOpen;
|
const drawerOpen = this.notificationDrawerOpen || this.apiDrawerOpen;
|
||||||
|
|
||||||
const drawerClasses = {
|
const drawerClasses = {
|
||||||
"pf-m-expanded": drawerOpen,
|
"pf-m-expanded": drawerOpen,
|
||||||
"pf-m-collapsed": !drawerOpen,
|
"pf-m-collapsed": !drawerOpen,
|
||||||
@ -198,18 +136,11 @@ export class AdminInterface extends WithLicenseSummary(AuthenticatedInterface) {
|
|||||||
|
|
||||||
return html` <ak-locale-context>
|
return html` <ak-locale-context>
|
||||||
<div class="pf-c-page">
|
<div class="pf-c-page">
|
||||||
<ak-page-navbar ?open=${this.sidebarOpen} @sidebar-toggle=${this.sidebarListener}>
|
<ak-enterprise-status interface="admin"></ak-enterprise-status>
|
||||||
<ak-version-banner></ak-version-banner>
|
<ak-version-banner></ak-version-banner>
|
||||||
<ak-enterprise-status interface="admin"></ak-enterprise-status>
|
<ak-admin-sidebar
|
||||||
</ak-page-navbar>
|
class="pf-c-page__sidebar ${classMap(sidebarClasses)}"
|
||||||
|
></ak-admin-sidebar>
|
||||||
<ak-sidebar class="${classMap(sidebarClasses)}">
|
|
||||||
${renderSidebarItems(AdminSidebarEntries)}
|
|
||||||
${this.licenseSummary?.status !== LicenseSummaryStatusEnum.Unlicensed
|
|
||||||
? renderSidebarItems(AdminSidebarEnterpriseEntries)
|
|
||||||
: nothing}
|
|
||||||
</ak-sidebar>
|
|
||||||
|
|
||||||
<div class="pf-c-page__drawer">
|
<div class="pf-c-page__drawer">
|
||||||
<div class="pf-c-drawer ${classMap(drawerClasses)}">
|
<div class="pf-c-drawer ${classMap(drawerClasses)}">
|
||||||
<div class="pf-c-drawer__main">
|
<div class="pf-c-drawer__main">
|
@ -1,97 +1,186 @@
|
|||||||
|
import { EVENT_SIDEBAR_TOGGLE } from "@goauthentik/common/constants";
|
||||||
|
import { me } from "@goauthentik/common/users";
|
||||||
|
import { AKElement } from "@goauthentik/elements/Base";
|
||||||
|
import {
|
||||||
|
CapabilitiesEnum,
|
||||||
|
WithCapabilitiesConfig,
|
||||||
|
} from "@goauthentik/elements/Interface/capabilitiesProvider";
|
||||||
|
import { WithVersion } from "@goauthentik/elements/Interface/versionProvider";
|
||||||
import { ID_REGEX, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route";
|
import { ID_REGEX, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route";
|
||||||
|
import { getRootStyle } from "@goauthentik/elements/utils/getRootStyle";
|
||||||
import { spread } from "@open-wc/lit-helpers";
|
import { spread } from "@open-wc/lit-helpers";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { TemplateResult, html, nothing } from "lit";
|
import { TemplateResult, html, nothing } from "lit";
|
||||||
import { repeat } from "lit/directives/repeat.js";
|
import { customElement, property, state } from "lit/decorators.js";
|
||||||
|
import { map } from "lit/directives/map.js";
|
||||||
|
|
||||||
// The second attribute type is of string[] to help with the 'activeWhen' control, which was
|
import { UiThemeEnum } from "@goauthentik/api";
|
||||||
// commonplace and singular enough to merit its own handler.
|
import type { SessionUser, UserSelf } from "@goauthentik/api";
|
||||||
type SidebarEntry = [
|
|
||||||
path: string | null,
|
|
||||||
label: string,
|
|
||||||
attributes?: Record<string, any> | string[] | null, // eslint-disable-line
|
|
||||||
children?: SidebarEntry[],
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
@customElement("ak-admin-sidebar")
|
||||||
* Recursively renders a sidebar entry.
|
export class AkAdminSidebar extends WithCapabilitiesConfig(WithVersion(AKElement)) {
|
||||||
*/
|
@property({ type: Boolean, reflect: true })
|
||||||
export function renderSidebarItem([
|
open = true;
|
||||||
path,
|
|
||||||
label,
|
|
||||||
attributes,
|
|
||||||
children,
|
|
||||||
]: SidebarEntry): TemplateResult {
|
|
||||||
const properties = Array.isArray(attributes)
|
|
||||||
? { ".activeWhen": attributes }
|
|
||||||
: (attributes ?? {});
|
|
||||||
|
|
||||||
if (path) {
|
@state()
|
||||||
properties.path = path;
|
impersonation: UserSelf["username"] | null = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
me().then((user: SessionUser) => {
|
||||||
|
this.impersonation = user.original ? user.user.username : null;
|
||||||
|
});
|
||||||
|
this.toggleOpen = this.toggleOpen.bind(this);
|
||||||
|
this.checkWidth = this.checkWidth.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`<ak-sidebar-item ${spread(properties)}>
|
// This has to be a bound method so the event listener can be removed on disconnection as
|
||||||
${label ? html`<span slot="label">${label}</span>` : nothing}
|
// needed.
|
||||||
${children ? renderSidebarItems(children) : nothing}
|
toggleOpen() {
|
||||||
</ak-sidebar-item>`;
|
this.open = !this.open;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkWidth() {
|
||||||
|
// This works just fine, but it assumes that the `--ak-sidebar--minimum-auto-width` is in
|
||||||
|
// REMs. If that changes, this code will have to be adjusted as well.
|
||||||
|
const minWidth =
|
||||||
|
parseFloat(getRootStyle("--ak-sidebar--minimum-auto-width")) *
|
||||||
|
parseFloat(getRootStyle("font-size"));
|
||||||
|
this.open = window.innerWidth >= minWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
window.addEventListener(EVENT_SIDEBAR_TOGGLE, this.toggleOpen);
|
||||||
|
window.addEventListener("resize", this.checkWidth);
|
||||||
|
// After connecting to the DOM, we can now perform this check to see if the sidebar should
|
||||||
|
// be open by default.
|
||||||
|
this.checkWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The symmetry (☟, ☝) here is critical in that you want to start adding these handlers after
|
||||||
|
// connection, and removing them before disconnection.
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
window.removeEventListener(EVENT_SIDEBAR_TOGGLE, this.toggleOpen);
|
||||||
|
window.removeEventListener("resize", this.checkWidth);
|
||||||
|
super.disconnectedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<ak-sidebar
|
||||||
|
class="pf-c-page__sidebar ${this.open ? "pf-m-expanded" : "pf-m-collapsed"} ${this
|
||||||
|
.activeTheme === UiThemeEnum.Light
|
||||||
|
? "pf-m-light"
|
||||||
|
: ""}"
|
||||||
|
>
|
||||||
|
${this.renderSidebarItems()}
|
||||||
|
</ak-sidebar>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
updated() {
|
||||||
|
// This is permissible as`:host.classList` is not one of the properties Lit uses as a
|
||||||
|
// scheduling trigger. This sort of shenanigans can trigger an loop, in that it will trigger
|
||||||
|
// a browser reflow, which may trigger some other styling the application is monitoring,
|
||||||
|
// triggering a re-render which triggers a browser reflow, ad infinitum. But we've been
|
||||||
|
// living with that since jQuery, and it's both well-known and fortunately rare.
|
||||||
|
|
||||||
|
// eslint-disable-next-line wc/no-self-class
|
||||||
|
this.classList.remove("pf-m-expanded", "pf-m-collapsed");
|
||||||
|
// eslint-disable-next-line wc/no-self-class
|
||||||
|
this.classList.add(this.open ? "pf-m-expanded" : "pf-m-collapsed");
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSidebarItems(): TemplateResult {
|
||||||
|
// The second attribute type is of string[] to help with the 'activeWhen' control, which was
|
||||||
|
// commonplace and singular enough to merit its own handler.
|
||||||
|
type SidebarEntry = [
|
||||||
|
path: string | null,
|
||||||
|
label: string,
|
||||||
|
attributes?: Record<string, any> | string[] | null, // eslint-disable-line
|
||||||
|
children?: SidebarEntry[],
|
||||||
|
];
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const sidebarContent: SidebarEntry[] = [
|
||||||
|
[null, msg("Dashboards"), { "?expanded": true }, [
|
||||||
|
["/administration/overview", msg("Overview")],
|
||||||
|
["/administration/dashboard/users", msg("User Statistics")],
|
||||||
|
["/administration/system-tasks", msg("System Tasks")]]],
|
||||||
|
[null, msg("Applications"), null, [
|
||||||
|
["/core/applications", msg("Applications"), [`^/core/applications/(?<slug>${SLUG_REGEX})$`]],
|
||||||
|
["/core/providers", msg("Providers"), [`^/core/providers/(?<id>${ID_REGEX})$`]],
|
||||||
|
["/outpost/outposts", msg("Outposts")]]],
|
||||||
|
[null, msg("Events"), null, [
|
||||||
|
["/events/log", msg("Logs"), [`^/events/log/(?<id>${UUID_REGEX})$`]],
|
||||||
|
["/events/rules", msg("Notification Rules")],
|
||||||
|
["/events/transports", msg("Notification Transports")]]],
|
||||||
|
[null, msg("Customization"), null, [
|
||||||
|
["/policy/policies", msg("Policies")],
|
||||||
|
["/core/property-mappings", msg("Property Mappings")],
|
||||||
|
["/blueprints/instances", msg("Blueprints")],
|
||||||
|
["/policy/reputation", msg("Reputation scores")]]],
|
||||||
|
[null, msg("Flows and Stages"), null, [
|
||||||
|
["/flow/flows", msg("Flows"), [`^/flow/flows/(?<slug>${SLUG_REGEX})$`]],
|
||||||
|
["/flow/stages", msg("Stages")],
|
||||||
|
["/flow/stages/prompts", msg("Prompts")]]],
|
||||||
|
[null, msg("Directory"), null, [
|
||||||
|
["/identity/users", msg("Users"), [`^/identity/users/(?<id>${ID_REGEX})$`]],
|
||||||
|
["/identity/groups", msg("Groups"), [`^/identity/groups/(?<id>${UUID_REGEX})$`]],
|
||||||
|
["/identity/roles", msg("Roles"), [`^/identity/roles/(?<id>${UUID_REGEX})$`]],
|
||||||
|
["/identity/initial-permissions", msg("Initial Permissions"), [`^/identity/initial-permissions/(?<id>${ID_REGEX})$`]],
|
||||||
|
["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?<slug>${SLUG_REGEX})$`]],
|
||||||
|
["/core/tokens", msg("Tokens and App passwords")],
|
||||||
|
["/flow/stages/invitations", msg("Invitations")]]],
|
||||||
|
[null, msg("System"), null, [
|
||||||
|
["/core/brands", msg("Brands")],
|
||||||
|
["/crypto/certificates", msg("Certificates")],
|
||||||
|
["/outpost/integrations", msg("Outpost Integrations")],
|
||||||
|
["/admin/settings", msg("Settings")]]],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Typescript requires the type here to correctly type the recursive path
|
||||||
|
type SidebarRenderer = (_: SidebarEntry) => TemplateResult;
|
||||||
|
|
||||||
|
const renderOneSidebarItem: SidebarRenderer = ([path, label, attributes, children]) => {
|
||||||
|
const properties = Array.isArray(attributes)
|
||||||
|
? { ".activeWhen": attributes }
|
||||||
|
: (attributes ?? {});
|
||||||
|
if (path) {
|
||||||
|
properties.path = path;
|
||||||
|
}
|
||||||
|
return html`<ak-sidebar-item ${spread(properties)}>
|
||||||
|
${label ? html`<span slot="label">${label}</span>` : nothing}
|
||||||
|
${map(children, renderOneSidebarItem)}
|
||||||
|
</ak-sidebar-item>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
return html`
|
||||||
|
${map(sidebarContent, renderOneSidebarItem)}
|
||||||
|
${this.renderEnterpriseMenu()}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEnterpriseMenu() {
|
||||||
|
return this.can(CapabilitiesEnum.IsEnterprise)
|
||||||
|
? html`
|
||||||
|
<ak-sidebar-item>
|
||||||
|
<span slot="label">${msg("Enterprise")}</span>
|
||||||
|
<ak-sidebar-item path="/enterprise/licenses">
|
||||||
|
<span slot="label">${msg("Licenses")}</span>
|
||||||
|
</ak-sidebar-item>
|
||||||
|
</ak-sidebar-item>
|
||||||
|
`
|
||||||
|
: nothing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
declare global {
|
||||||
* Recursively renders a collection of sidebar entries.
|
interface HTMLElementTagNameMap {
|
||||||
*/
|
"ak-admin-sidebar": AkAdminSidebar;
|
||||||
export function renderSidebarItems(entries: readonly SidebarEntry[]) {
|
}
|
||||||
return repeat(entries, ([path, label]) => path || label, renderSidebarItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prettier-ignore
|
|
||||||
export const AdminSidebarEntries: readonly SidebarEntry[] = [
|
|
||||||
[null, msg("Dashboards"), { "?expanded": true }, [
|
|
||||||
["/administration/overview", msg("Overview")],
|
|
||||||
["/administration/dashboard/users", msg("User Statistics")],
|
|
||||||
["/administration/system-tasks", msg("System Tasks")]]
|
|
||||||
],
|
|
||||||
[null, msg("Applications"), null, [
|
|
||||||
["/core/applications", msg("Applications"), [`^/core/applications/(?<slug>${SLUG_REGEX})$`]],
|
|
||||||
["/core/providers", msg("Providers"), [`^/core/providers/(?<id>${ID_REGEX})$`]],
|
|
||||||
["/outpost/outposts", msg("Outposts")]]
|
|
||||||
],
|
|
||||||
[null, msg("Events"), null, [
|
|
||||||
["/events/log", msg("Logs"), [`^/events/log/(?<id>${UUID_REGEX})$`]],
|
|
||||||
["/events/rules", msg("Notification Rules")],
|
|
||||||
["/events/transports", msg("Notification Transports")]]
|
|
||||||
],
|
|
||||||
[null, msg("Customization"), null, [
|
|
||||||
["/policy/policies", msg("Policies")],
|
|
||||||
["/core/property-mappings", msg("Property Mappings")],
|
|
||||||
["/blueprints/instances", msg("Blueprints")],
|
|
||||||
["/policy/reputation", msg("Reputation scores")]]
|
|
||||||
],
|
|
||||||
[null, msg("Flows and Stages"), null, [
|
|
||||||
["/flow/flows", msg("Flows"), [`^/flow/flows/(?<slug>${SLUG_REGEX})$`]],
|
|
||||||
["/flow/stages", msg("Stages")],
|
|
||||||
["/flow/stages/prompts", msg("Prompts")]]
|
|
||||||
],
|
|
||||||
[null, msg("Directory"), null, [
|
|
||||||
["/identity/users", msg("Users"), [`^/identity/users/(?<id>${ID_REGEX})$`]],
|
|
||||||
["/identity/groups", msg("Groups"), [`^/identity/groups/(?<id>${UUID_REGEX})$`]],
|
|
||||||
["/identity/roles", msg("Roles"), [`^/identity/roles/(?<id>${UUID_REGEX})$`]],
|
|
||||||
["/identity/initial-permissions", msg("Initial Permissions"), [`^/identity/initial-permissions/(?<id>${ID_REGEX})$`]],
|
|
||||||
["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?<slug>${SLUG_REGEX})$`]],
|
|
||||||
["/core/tokens", msg("Tokens and App passwords")],
|
|
||||||
["/flow/stages/invitations", msg("Invitations")]]
|
|
||||||
],
|
|
||||||
[null, msg("System"), null, [
|
|
||||||
["/core/brands", msg("Brands")],
|
|
||||||
["/crypto/certificates", msg("Certificates")],
|
|
||||||
["/outpost/integrations", msg("Outpost Integrations")],
|
|
||||||
["/admin/settings", msg("Settings")]]
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
// prettier-ignore
|
|
||||||
export const AdminSidebarEnterpriseEntries: readonly SidebarEntry[] = [
|
|
||||||
[null, msg("Enterprise"), null, [
|
|
||||||
["/enterprise/licenses", msg("Licenses"), null]
|
|
||||||
],
|
|
||||||
]]
|
|
||||||
|
5
web/src/admin/AdminInterface/index.ts
Normal file
5
web/src/admin/AdminInterface/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { AdminInterface } from "./AdminInterface";
|
||||||
|
import "./AdminInterface";
|
||||||
|
|
||||||
|
export { AdminInterface };
|
||||||
|
export default AdminInterface;
|
@ -94,13 +94,10 @@ export class AdminOverviewPage extends AdminOverviewBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
const username = this.user?.user.name || this.user?.user.username;
|
const name = this.user?.user.name ?? this.user?.user.username;
|
||||||
|
|
||||||
return html` <ak-page-header
|
return html`<ak-page-header description=${msg("General system status")} ?hasIcon=${false}>
|
||||||
header=${msg(str`Welcome, ${username || ""}.`)}
|
<span slot="header"> ${msg(str`Welcome, ${name || ""}.`)} </span>
|
||||||
description=${msg("General system status")}
|
|
||||||
?hasIcon=${false}
|
|
||||||
>
|
|
||||||
</ak-page-header>
|
</ak-page-header>
|
||||||
<section class="pf-c-page__main-section">
|
<section class="pf-c-page__main-section">
|
||||||
<div class="pf-l-grid pf-m-gutter">
|
<div class="pf-l-grid pf-m-gutter">
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
|
import { first } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/components/ak-number-input";
|
import "@goauthentik/components/ak-number-input";
|
||||||
import "@goauthentik/components/ak-switch-input";
|
import "@goauthentik/components/ak-switch-input";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
@ -183,14 +184,20 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
|
|||||||
label=${msg("Reputation: lower limit")}
|
label=${msg("Reputation: lower limit")}
|
||||||
required
|
required
|
||||||
name="reputationLowerLimit"
|
name="reputationLowerLimit"
|
||||||
value="${this._settings?.reputationLowerLimit ?? DEFAULT_REPUTATION_LOWER_LIMIT}"
|
value="${first(
|
||||||
|
this._settings?.reputationLowerLimit,
|
||||||
|
DEFAULT_REPUTATION_LOWER_LIMIT,
|
||||||
|
)}"
|
||||||
help=${msg("Reputation cannot decrease lower than this value. Zero or negative.")}
|
help=${msg("Reputation cannot decrease lower than this value. Zero or negative.")}
|
||||||
></ak-number-input>
|
></ak-number-input>
|
||||||
<ak-number-input
|
<ak-number-input
|
||||||
label=${msg("Reputation: upper limit")}
|
label=${msg("Reputation: upper limit")}
|
||||||
required
|
required
|
||||||
name="reputationUpperLimit"
|
name="reputationUpperLimit"
|
||||||
value="${this._settings?.reputationUpperLimit ?? DEFAULT_REPUTATION_UPPER_LIMIT}"
|
value="${first(
|
||||||
|
this._settings?.reputationUpperLimit,
|
||||||
|
DEFAULT_REPUTATION_UPPER_LIMIT,
|
||||||
|
)}"
|
||||||
help=${msg("Reputation cannot increase higher than this value. Zero or positive.")}
|
help=${msg("Reputation cannot increase higher than this value. Zero or positive.")}
|
||||||
></ak-number-input>
|
></ak-number-input>
|
||||||
<ak-form-element-horizontal label=${msg("Footer links")} name="footerLinks">
|
<ak-form-element-horizontal label=${msg("Footer links")} name="footerLinks">
|
||||||
@ -250,7 +257,7 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
|
|||||||
label=${msg("Default token length")}
|
label=${msg("Default token length")}
|
||||||
required
|
required
|
||||||
name="defaultTokenLength"
|
name="defaultTokenLength"
|
||||||
value="${this._settings?.defaultTokenLength ?? 60}"
|
value="${first(this._settings?.defaultTokenLength, 60)}"
|
||||||
help=${msg("Default length of generated tokens")}
|
help=${msg("Default length of generated tokens")}
|
||||||
></ak-number-input>
|
></ak-number-input>
|
||||||
`;
|
`;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user