Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@

All notable changes to this project will be documented in this file.

## 4.0.0 (UNRELEASED)
### 📝 Notes
* The support for Nextcloud versions below 30 has been removed,
this means some functions like filename validation will now only
work with the capabilities provided by Nextcloud 30 or newer.

## 4.0.0-beta.1 - 2025-11-27
### 🐛 Fixed bugs
* fix: actions type exports by @skjnldsv in https://github.com/nextcloud-libraries/nextcloud-files/pull/1381
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ This library provides three kinds of utils:
2. Geneal purpose function related to files or folders, like filename validation.
3. Functions and classes to interact with the Nextcloud **files** app, like registering a new view or a file action.

## Compatibility

| `@nextcloud/files` version | Supported | Nextcloud version |
|----------------------------|-----------|-------------------|
| 4.x | ✅ | 30+ |
| 3.x | ✅ | 26+ |
| 2.x | ❌ | 23-25 |
| 1.x | ❌ | 20-22 |

## Usage examples

### Files app
Expand Down
21 changes: 5 additions & 16 deletions __tests__/utils/filename-validation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,6 @@ describe('validateFilename', () => {
expect(() => validateFilename('.htaccess')).toThrowError(InvalidFilenameError)
})

it('has fallback invalid extension', async () => {
expect(() => validateFilename('file.txt.part')).toThrowError(InvalidFilenameError)
expect(() => validateFilename('file.txt.filepart')).toThrowError(InvalidFilenameError)
})

// Nextcloud 29
it('fallback fetching forbidden characters from oc config', async () => {
window._oc_config = { forbidden_filenames_characters: ['=', '?'] }
expect(() => validateFilename('foo.bar')).not.toThrow()
expect(() => validateFilename('foo=bar')).toThrowError(InvalidFilenameError)
expect(() => validateFilename('foo?bar')).toThrowError(InvalidFilenameError)
})

// Nextcloud 30+
it('fetches forbidden characters from capabilities', async () => {
nextcloudCapabilities.getCapabilities.mockImplementation(() => ({ files: { forbidden_filename_characters: ['=', '?'] } }))
Expand Down Expand Up @@ -136,14 +123,16 @@ describe('validateFilename', () => {
})

it('sets error properties correctly on invalid extension', async () => {
nextcloudCapabilities.getCapabilities.mockImplementation(() => ({ files: { forbidden_filename_extensions: ['.txt'] } }))

try {
validateFilename('file.part')
validateFilename('file.txt')
expect(true, 'should not be reached').toBeFalsy()
} catch (error) {
expect(error).toBeInstanceOf(InvalidFilenameError)
expect((error as InvalidFilenameError).reason).toBe(InvalidFilenameErrorReason.Extension)
expect((error as InvalidFilenameError).segment).toBe('.part')
expect((error as InvalidFilenameError).filename).toBe('file.part')
expect((error as InvalidFilenameError).segment).toBe('.txt')
expect((error as InvalidFilenameError).filename).toBe('file.txt')
}
})

Expand Down
8 changes: 3 additions & 5 deletions lib/utils/filename-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function validateFilename(filename: string): void {

// Handle forbidden characters
// This needs to be done first as the other checks are case insensitive!
const forbiddenCharacters = capabilities.forbidden_filename_characters ?? window._oc_config?.forbidden_filenames_characters ?? ['/', '\\']
const forbiddenCharacters = capabilities.forbidden_filename_characters ?? ['/', '\\']
for (const character of forbiddenCharacters) {
if (filename.includes(character)) {
throw new InvalidFilenameError({ segment: character, reason: InvalidFilenameErrorReason.Character, filename })
Expand All @@ -102,9 +102,7 @@ export function validateFilename(filename: string): void {
throw new InvalidFilenameError({ filename, segment: basename, reason: InvalidFilenameErrorReason.ReservedName })
}

// The legacy 'blacklist_files_regex' was hardcoded to the extension '.part' and '.filepart'
// So if the new (Nextcloud 30) capability is not awailable then we fallback to that
const forbiddenFilenameExtensions = capabilities.forbidden_filename_extensions ?? ['.part', '.filepart']
const forbiddenFilenameExtensions = capabilities.forbidden_filename_extensions ?? []
for (const extension of forbiddenFilenameExtensions) {
if (filename.length > extension.length && filename.endsWith(extension)) {
throw new InvalidFilenameError({ segment: extension, reason: InvalidFilenameErrorReason.Extension, filename })
Expand All @@ -114,7 +112,7 @@ export function validateFilename(filename: string): void {

/**
* Check the validity of a filename
* This is a convinient wrapper for `checkFilenameValidity` to only return a boolean for the valid
* This is a convenient wrapper for `checkFilenameValidity` to only return a boolean for the valid
* @param filename Filename to check validity
*/
export function isFilenameValid(filename: string): boolean {
Expand Down
2 changes: 0 additions & 2 deletions lib/window.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ declare global {

_oc_config?: {
forbidden_filenames_characters: string[]
/** @deprecated */
blacklist_files_regex?: string
}
}
}