mirror of
https://github.com/goauthentik/authentik.git
synced 2026-06-17 19:09:11 +03:00
web/admin: fix file upload not preserving extension for custom names with dots (#19548)
* web/admin: fix file upload not preserving extension for custom names with dots Overview: The `hasBasenameExtension()` function in `FileUploadForm.ts` incorrectly determined whether a custom filename already had an extension by checking if it contained any dot at position > 0. This caused filenames like "e._.e" to be treated as having an extension, so the original file's extension was not appended. The file would be saved as "e._.e" instead of "e._.e.jpg", which caused `mimetypes.guess_type()` to return `None` (since ".e" is not a recognized extension) and the backend to fall back to "application/octet-stream". Removed `hasBasenameExtension()` entirely. Since the UI explicitly states "Optionally rename the file (without extension)", we now always append the original file's extension when a custom name is provided. Testing: 1. Upload a JPG file with custom name "e" --> saves as "e.jpg", and is detected as "image/jpeg" 2. Upload a JPG file with custom name "e._.e" --> now saves as "e._.e.jpg",and is detected as "image/jpeg" Motivation: Fixes incorrect MIME type detection for uploaded files when users provide custom filenames containing dots. * web: lint * web: Ken's suggestion
This commit is contained in:
+35
-48
@@ -3013,34 +3013,6 @@ paths:
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
/core/authenticated_sessions/bulk_delete/:
|
||||
delete:
|
||||
operationId: core_authenticated_sessions_bulk_delete
|
||||
description: Bulk revoke all sessions for multiple users
|
||||
parameters:
|
||||
- in: query
|
||||
name: user_pks
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
description: List of user IDs to revoke all sessions for
|
||||
required: true
|
||||
tags:
|
||||
- core
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SessionDeleteResponse'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
/core/authenticated_sessions/{uuid}/:
|
||||
get:
|
||||
operationId: core_authenticated_sessions_retrieve
|
||||
@@ -3116,6 +3088,34 @@ paths:
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
/core/authenticated_sessions/bulk_delete/:
|
||||
delete:
|
||||
operationId: core_authenticated_sessions_bulk_delete_destroy
|
||||
description: Bulk revoke all sessions for multiple users
|
||||
parameters:
|
||||
- in: query
|
||||
name: user_pks
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
description: List of user IDs to revoke all sessions for
|
||||
required: true
|
||||
tags:
|
||||
- core
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/BulkDeleteSessionResponse'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
/core/brands/:
|
||||
get:
|
||||
operationId: core_brands_list
|
||||
@@ -34725,17 +34725,6 @@ components:
|
||||
- orphaned
|
||||
- unknown
|
||||
type: string
|
||||
BulkDeleteSession:
|
||||
type: object
|
||||
description: Serializer for bulk deleting authenticated sessions by user
|
||||
properties:
|
||||
user_ids:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
description: List of user IDs to revoke all sessions for
|
||||
required:
|
||||
- user_pks
|
||||
Brand:
|
||||
type: object
|
||||
description: Brand Serializer
|
||||
@@ -34878,6 +34867,13 @@ components:
|
||||
additionalProperties: {}
|
||||
required:
|
||||
- domain
|
||||
BulkDeleteSessionResponse:
|
||||
type: object
|
||||
properties:
|
||||
deleted:
|
||||
type: integer
|
||||
required:
|
||||
- deleted
|
||||
Cache:
|
||||
type: object
|
||||
description: Generic cache stats for an object
|
||||
@@ -53288,15 +53284,6 @@ components:
|
||||
required:
|
||||
- healthy
|
||||
- version
|
||||
SessionDeleteResponse:
|
||||
type: object
|
||||
description: Response for bulk session deletion
|
||||
properties:
|
||||
deleted:
|
||||
type: integer
|
||||
description: Number of sessions deleted
|
||||
required:
|
||||
- deleted
|
||||
SessionEndChallenge:
|
||||
type: object
|
||||
description: Challenge for ending a session
|
||||
|
||||
@@ -45,12 +45,6 @@ function getFileExtension(fileName: string): string {
|
||||
return fileName.slice(lastDot);
|
||||
}
|
||||
|
||||
function hasBasenameExtension(fileName: string): boolean {
|
||||
const baseName = fileName.split("/").pop() ?? fileName;
|
||||
const lastDot = baseName.lastIndexOf(".");
|
||||
return lastDot > 0;
|
||||
}
|
||||
|
||||
@customElement("ak-file-upload-form")
|
||||
export class FileUploadForm extends Form<Record<string, unknown>> {
|
||||
@property({ type: String, useDefault: true })
|
||||
@@ -89,17 +83,10 @@ export class FileUploadForm extends Form<Record<string, unknown>> {
|
||||
const api = new AdminApi(DEFAULT_CONFIG);
|
||||
const customName = typeof data.name === "string" ? data.name.trim() : "";
|
||||
|
||||
// If custom name provided, validate and append original extension
|
||||
// Only validate the original filename if no custom name is provided
|
||||
let finalName = this.selectedFile.name;
|
||||
if (customName) {
|
||||
assertValidFileName(customName);
|
||||
const ext = getFileExtension(this.selectedFile.name);
|
||||
finalName =
|
||||
ext && !hasBasenameExtension(customName) ? `${customName}${ext}` : customName;
|
||||
} else {
|
||||
assertValidFileName(this.selectedFile.name);
|
||||
}
|
||||
// If custom name provided, append original file extension; otherwise use original filename
|
||||
const finalName = customName
|
||||
? `${customName}${getFileExtension(this.selectedFile.name)}`
|
||||
: this.selectedFile.name;
|
||||
|
||||
assertValidFileName(finalName);
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ export class UserBulkRevokeSessionsForm extends ModalButton {
|
||||
if (userIds.length > 0) {
|
||||
const response = await new CoreApi(
|
||||
DEFAULT_CONFIG,
|
||||
).coreAuthenticatedSessionsBulkDelete({
|
||||
).coreAuthenticatedSessionsBulkDeleteDestroy({
|
||||
userPks: userIds,
|
||||
});
|
||||
this.revokedCount = response.deleted || 0;
|
||||
|
||||
Reference in New Issue
Block a user