Skip to content

Commit

Permalink
feat(files): update mtime on attributes tampering
Browse files Browse the repository at this point in the history
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
  • Loading branch information
skjnldsv committed Mar 17, 2023
1 parent cd3d69a commit 4f27fcb
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 6 deletions.
76 changes: 73 additions & 3 deletions __tests__/files/file.spec.ts
Expand Up @@ -7,7 +7,9 @@ describe('File creation', () => {
const file = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma'
owner: 'emma',
mtime: new Date(Date.UTC(2023, 0, 1, 0, 0, 0)),
crtime: new Date(Date.UTC(1990, 0, 1, 0, 0, 0)),
})

expect(file).toBeInstanceOf(File)
Expand All @@ -19,6 +21,10 @@ describe('File creation', () => {
expect(file.size).toBeUndefined()
expect(file.attributes).toStrictEqual({})

// Times
expect(file.mtime?.toISOString()).toBe('2023-01-01T00:00:00.000Z')
expect(file.crtime?.toISOString()).toBe('1990-01-01T00:00:00.000Z')

// path checks
expect(file.basename).toBe('picture.jpg')
expect(file.extension).toBe('.jpg')
Expand Down Expand Up @@ -87,38 +93,48 @@ describe('File data change', () => {
const file = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma'
owner: 'emma',
mtime: new Date(Date.UTC(2023, 0, 1, 0, 0, 0)),
})

expect(file.basename).toBe('picture.jpg')
expect(file.dirname).toBe('/')
expect(file.root).toBe('/files/emma/Photos')
expect(file.mtime?.toISOString()).toBe('2023-01-01T00:00:00.000Z')

file.rename('picture-old.jpg')

expect(file.basename).toBe('picture-old.jpg')
expect(file.dirname).toBe('/')
expect(file.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture-old.jpg')
expect(file.root).toBe('/files/emma/Photos')

// Check that mtime has been updated
expect(file.mtime?.getDate()).toBe(new Date().getDate())
})

test('Moving a file', () => {
const file = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma'
owner: 'emma',
mtime: new Date(Date.UTC(2023, 0, 1, 0, 0, 0)),
})

expect(file.basename).toBe('picture.jpg')
expect(file.dirname).toBe('/')
expect(file.root).toBe('/files/emma/Photos')
expect(file.mtime?.toISOString()).toBe('2023-01-01T00:00:00.000Z')

file.move('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old.jpg')

expect(file.basename).toBe('picture-old.jpg')
expect(file.dirname).toBe('/')
expect(file.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old.jpg')
expect(file.root).toBe('/files/emma/Pictures')

// Check that mtime has been updated
expect(file.mtime?.getDate()).toBe(new Date().getDate())
})

test('Moving a file to a different folder with root', () => {
Expand All @@ -141,3 +157,57 @@ describe('File data change', () => {
expect(file.root).toBe('/files/emma')
})
})


describe('Altering attributes updates mtime', () => {
test('mtime is updated on existing attribute', () => {
const file = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma',
mime: 'image/jpeg',
owner: 'emma',
mtime: new Date(Date.UTC(1990, 0, 1, 0, 0, 0)),
attributes: {
test: true
},
})
expect(file.attributes.test).toBe(true)
file.attributes.test = false

// Check that mtime has been updated
expect(file.mtime?.getDate()).toBe(new Date().getDate())
expect(file.attributes.test).toBe(false)
})

test('mtime is updated on new attribute', () => {
const file = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma',
mime: 'image/jpeg',
owner: 'emma',
mtime: new Date(Date.UTC(1990, 0, 1, 0, 0, 0)),
})
expect(file.attributes.test).toBeFalsy()
file.attributes.test = true

// Check that mtime has been updated
expect(file.mtime?.getDate()).toBe(new Date().getDate())
expect(file.attributes.test).toBe(true)
})

test('mtime is updated on deleted attribute', () => {
const file = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma',
mime: 'image/jpeg',
owner: 'emma',
mtime: new Date(Date.UTC(1990, 0, 1, 0, 0, 0)),
attributes: {
test: true
},
})
expect(file.attributes.test).toBe(true)
delete file.attributes.test

// Check that mtime has been updated
expect(file.mtime?.getDate()).toBe(new Date().getDate())
expect(file.attributes.test).toBeUndefined()
})
})
2 changes: 1 addition & 1 deletion __tests__/files/node.spec.ts
Expand Up @@ -229,4 +229,4 @@ describe('Root and paths detection', () => {
})
expect(file1.dirname).toBe('/')
})
})
})
37 changes: 35 additions & 2 deletions lib/files/node.ts
Expand Up @@ -24,17 +24,35 @@ import { Permission } from '../permissions'
import { FileType } from './fileType'
import NodeData, { Attribute, validateData } from './nodeData'


export abstract class Node {
private _data: NodeData
private _attributes: Attribute[]
private _attributes: Attribute
private _knownDavService = /(remote|public)\.php\/(web)?dav/i

constructor(data: NodeData, davService?: RegExp) {
// Validate data
validateData(data)

this._data = data
this._attributes = data.attributes || {} as any

const handler = {
set: (target: Attribute, prop: string, value: any): any => {
// Edit modification time
this._data['mtime'] = new Date()
// Apply original changes
return Reflect.set(target, prop, value)
},
deleteProperty: (target: Attribute, prop: string) => {
// Edit modification time
this._data['mtime'] = new Date()
// Apply original changes
return Reflect.deleteProperty(target, prop)
},
} as ProxyHandler<any>

// Proxy the attributes to update the mtime on change
this._attributes = new Proxy(data.attributes || {} as any, handler)
delete this._data.attributes

if (davService) {
Expand Down Expand Up @@ -87,6 +105,20 @@ export abstract class Node {
return this._data.mime
}

/**
* Get the file modification time
*/
get mtime(): Date|undefined {
return this._data.mtime
}

/**
* Get the file creation time
*/
get crtime(): Date|undefined {
return this._data.crtime
}

/**
* Get the file size
*/
Expand Down Expand Up @@ -164,6 +196,7 @@ export abstract class Node {
*/
move(destination: string) {
this._data.source = destination
this._data.mtime = new Date()
}

/**
Expand Down

0 comments on commit 4f27fcb

Please sign in to comment.