Add allowAnonymousViews option (#1152)

Add allowAnonymousViews option
This commit is contained in:
Max Wu 2019-09-23 10:17:54 +08:00 committed by GitHub
commit fdbfb71d97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 13 deletions

1
app.js
View File

@ -180,6 +180,7 @@ app.locals.serverURL = config.serverURL
app.locals.sourceURL = config.sourceURL app.locals.sourceURL = config.sourceURL
app.locals.allowAnonymous = config.allowAnonymous app.locals.allowAnonymous = config.allowAnonymous
app.locals.allowAnonymousEdits = config.allowAnonymousEdits app.locals.allowAnonymousEdits = config.allowAnonymousEdits
app.locals.permission = config.permission
app.locals.allowPDFExport = config.allowPDFExport app.locals.allowPDFExport = config.allowPDFExport
app.locals.authProviders = { app.locals.authProviders = {
facebook: config.isFacebookEnable, facebook: config.isFacebookEnable,

View File

@ -31,6 +31,7 @@ module.exports = {
useCDN: true, useCDN: true,
allowAnonymous: true, allowAnonymous: true,
allowAnonymousEdits: false, allowAnonymousEdits: false,
allowAnonymousViews: true,
allowFreeURL: false, allowFreeURL: false,
forbiddenNoteIDs: ['robots.txt', 'favicon.ico', 'api'], forbiddenNoteIDs: ['robots.txt', 'favicon.ico', 'api'],
defaultPermission: 'editable', defaultPermission: 'editable',

View File

@ -27,6 +27,7 @@ module.exports = {
useCDN: toBooleanConfig(process.env.CMD_USECDN), useCDN: toBooleanConfig(process.env.CMD_USECDN),
allowAnonymous: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS), allowAnonymous: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS),
allowAnonymousEdits: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS_EDITS), allowAnonymousEdits: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS_EDITS),
allowAnonymousViews: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS_VIEWS),
allowFreeURL: toBooleanConfig(process.env.CMD_ALLOW_FREEURL), allowFreeURL: toBooleanConfig(process.env.CMD_ALLOW_FREEURL),
forbiddenNoteIDs: toArrayConfig(process.env.CMD_FORBIDDEN_NOTE_IDS), forbiddenNoteIDs: toArrayConfig(process.env.CMD_FORBIDDEN_NOTE_IDS),
defaultPermission: process.env.CMD_DEFAULT_PERMISSION, defaultPermission: process.env.CMD_DEFAULT_PERMISSION,

View File

@ -68,11 +68,17 @@ if (config.ldap.tlsca) {
// Permission // Permission
config.permission = Permission config.permission = Permission
if (!config.allowAnonymous && !config.allowAnonymousEdits) { let defaultPermission = config.permission.editable
if (!config.allowAnonymous && !config.allowAnonymousViews) {
delete config.permission.freely
delete config.permission.editable
delete config.permission.locked
defaultPermission = config.permission.limited
} else if (!config.allowAnonymous && !config.allowAnonymousEdits) {
delete config.permission.freely delete config.permission.freely
} }
if (!(config.defaultPermission in config.permission)) { if (!(config.defaultPermission in config.permission)) {
config.defaultPermission = config.permission.editable config.defaultPermission = defaultPermission
} }
// cache result, cannot change config in runtime!!! // cache result, cannot change config in runtime!!!

View File

@ -57,6 +57,19 @@ class RealtimeClientConnection {
return config.allowAnonymous || config.allowAnonymousEdits return config.allowAnonymous || config.allowAnonymousEdits
} }
getAvailablePermissions () {
// TODO: move this method to config module
const availablePermission = Object.assign({}, config.permission)
if (!config.allowAnonymous && !config.allowAnonymousViews) {
delete availablePermission.freely
delete availablePermission.editable
delete availablePermission.locked
} else if (!config.allowAnonymous && !config.allowAnonymousEdits) {
delete availablePermission.freely
}
return availablePermission
}
getCurrentUser () { getCurrentUser () {
if (!this.socket.id) return if (!this.socket.id) return
return this.realtime.getUserFromUserPool(this.socket.id) return this.realtime.getUserFromUserPool(this.socket.id)
@ -211,7 +224,7 @@ class RealtimeClientConnection {
const note = this.getCurrentNote() const note = this.getCurrentNote()
// Only owner can change permission // Only owner can change permission
if (!this.isNoteOwner()) return if (!this.isNoteOwner()) return
if (!this.isAnonymousEnable() && permission === 'freely') return if (!(permission in this.getAvailablePermissions())) return
this.changeNotePermission(permission) this.changeNotePermission(permission)
.then(() => { .then(() => {

View File

@ -15,12 +15,12 @@
<a id="permissionLabel" class="ui-permission-label text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> <a id="permissionLabel" class="ui-permission-label text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
</a> </a>
<ul class="dropdown-menu" aria-labelledby="permissionLabel"> <ul class="dropdown-menu" aria-labelledby="permissionLabel">
<li class="ui-permission-freely"<% if(!allowAnonymous && !allowAnonymousEdits) { %> style="display: none;"<% } %>><a><i class="fa fa-leaf fa-fw"></i> Freely - Anyone can edit</a></li> <li class="ui-permission-freely"<% if(!('freely' in permission)) { %> style="display: none;"<% } %>><a><i class="fa fa-leaf fa-fw"></i> Freely - Anyone can edit</a></li>
<li class="ui-permission-editable"><a><i class="fa fa-shield fa-fw"></i> Editable - Signed-in people can edit</a></li> <li class="ui-permission-editable"<% if(!('editable' in permission)) { %> style="display: none;"<% } %>><a><i class="fa fa-shield fa-fw"></i> Editable - Signed-in people can edit</a></li>
<li class="ui-permission-limited"><a><i class="fa fa-id-card fa-fw"></i> Limited - Signed-in people can edit (forbid guests)</a></li> <li class="ui-permission-limited"<% if(!('limited' in permission)) { %> style="display: none;"<% } %>><a><i class="fa fa-id-card fa-fw"></i> Limited - Signed-in people can edit (forbid guests)</a></li>
<li class="ui-permission-locked"><a><i class="fa fa-lock fa-fw"></i> Locked - Only owner can edit</a></li> <li class="ui-permission-locked"<% if(!('locked' in permission)) { %> style="display: none;"<% } %>><a><i class="fa fa-lock fa-fw"></i> Locked - Only owner can edit</a></li>
<li class="ui-permission-protected"><a><i class="fa fa-umbrella fa-fw"></i> Protected - Only owner can edit (forbid guests)</a></li> <li class="ui-permission-protected"<% if(!('protected' in permission)) { %> style="display: none;"<% } %>><a><i class="fa fa-umbrella fa-fw"></i> Protected - Only owner can edit (forbid guests)</a></li>
<li class="ui-permission-private"><a><i class="fa fa-hand-stop-o fa-fw"></i> Private - Only owner can view &amp; edit</a></li> <li class="ui-permission-private"<% if(!('private' in permission)) { %> style="display: none;"<% } %>><a><i class="fa fa-hand-stop-o fa-fw"></i> Private - Only owner can view &amp; edit</a></li>
<li class="divider"></li> <li class="divider"></li>
<li class="ui-delete-note"><a><i class="fa fa-trash-o fa-fw"></i> Delete this note</a></li> <li class="ui-delete-note"><a><i class="fa fa-trash-o fa-fw"></i> Delete this note</a></li>
</ul> </ul>

View File

@ -56,7 +56,15 @@ describe('realtime#socket event', function () {
}) })
configMock = { configMock = {
fullversion: '1.5.0', fullversion: '1.5.0',
minimumCompatibleVersion: '1.0.0' minimumCompatibleVersion: '1.0.0',
permission: {
freely: 'freely',
editable: 'editable',
limited: 'limited',
locked: 'locked',
protected: 'protected',
private: 'private'
}
} }
mock('../../lib/logger', { mock('../../lib/logger', {
error: () => { error: () => {
@ -522,9 +530,10 @@ describe('realtime#socket event', function () {
}, 5) }, 5)
}) })
it('should change permission to freely when config allowAnonymous and allowAnonymousEdits are true', function (done) { it('should change permission to freely when config allowAnonymous, allowAnonymousEdits and allowAnonymousViews are true', function (done) {
configMock.allowAnonymous = true configMock.allowAnonymous = true
configMock.allowAnonymousEdits = true configMock.allowAnonymousEdits = true
configMock.allowAnonymousViews = true
realtime.notes[noteId].socks = [clientSocket, undefined, otherClient] realtime.notes[noteId].socks = [clientSocket, undefined, otherClient]
permissionFunc('freely') permissionFunc('freely')
@ -539,9 +548,10 @@ describe('realtime#socket event', function () {
}, 5) }, 5)
}) })
it('should not change permission to freely when config allowAnonymous and allowAnonymousEdits are false', function (done) { it('should not change permission to freely when config allowAnonymous, allowAnonymousEdits and allowAnonymousViews are false', function (done) {
configMock.allowAnonymous = false configMock.allowAnonymous = false
configMock.allowAnonymousEdits = false configMock.allowAnonymousEdits = false
configMock.allowAnonymousViews = false
realtime.notes[noteId].socks = [clientSocket, undefined, otherClient] realtime.notes[noteId].socks = [clientSocket, undefined, otherClient]
permissionFunc('freely') permissionFunc('freely')
@ -556,6 +566,7 @@ describe('realtime#socket event', function () {
it('should change permission to freely when config allowAnonymous is true', function (done) { it('should change permission to freely when config allowAnonymous is true', function (done) {
configMock.allowAnonymous = true configMock.allowAnonymous = true
configMock.allowAnonymousEdits = false configMock.allowAnonymousEdits = false
configMock.allowAnonymousViews = false
realtime.notes[noteId].socks = [clientSocket, undefined, otherClient] realtime.notes[noteId].socks = [clientSocket, undefined, otherClient]
permissionFunc('freely') permissionFunc('freely')
@ -570,9 +581,58 @@ describe('realtime#socket event', function () {
}, 5) }, 5)
}) })
it('should change permission to freely when config allowAnonymousEdits is true', function (done) { it('should not change permission to freely when config allowAnonymousEdits is true', function (done) {
configMock.allowAnonymous = false configMock.allowAnonymous = false
configMock.allowAnonymousEdits = true configMock.allowAnonymousEdits = true
configMock.allowAnonymousViews = false
realtime.notes[noteId].socks = [clientSocket, undefined, otherClient]
permissionFunc('freely')
setTimeout(() => {
assert(modelsMock.Note.update.called === false)
assert(checkViewPermissionSpy.called === false)
done()
}, 5)
})
it('should not change permission to freely when config allowAnonymousViews is true', function (done) {
configMock.allowAnonymous = false
configMock.allowAnonymousEdits = false
configMock.allowAnonymousViews = true
realtime.notes[noteId].socks = [clientSocket, undefined, otherClient]
permissionFunc('freely')
setTimeout(() => {
assert(modelsMock.Note.update.called === false)
assert(checkViewPermissionSpy.called === false)
done()
}, 5)
})
it('should change permission to editable when config allowAnonymousViews is true', function (done) {
configMock.allowAnonymous = false
configMock.allowAnonymousEdits = false
configMock.allowAnonymousViews = true
realtime.notes[noteId].socks = [clientSocket, undefined, otherClient]
permissionFunc('editable')
setTimeout(() => {
assert(checkViewPermissionSpy.callCount === 2)
assert(otherClient.emit.called === false)
assert(otherClient.disconnect.called === false)
assert(clientSocket.emit.called === false)
assert(clientSocket.disconnect.called === false)
done()
}, 5)
})
it('should change permission to freely when config allowAnonymousEdits and allowAnonymousViews are false true', function (done) {
configMock.allowAnonymous = false
configMock.allowAnonymousEdits = true
configMock.allowAnonymousViews = true
realtime.notes[noteId].socks = [clientSocket, undefined, otherClient] realtime.notes[noteId].socks = [clientSocket, undefined, otherClient]
permissionFunc('freely') permissionFunc('freely')
@ -586,5 +646,23 @@ describe('realtime#socket event', function () {
done() done()
}, 5) }, 5)
}) })
it('should change permission to editable when config allowAnonymousEdits and allowAnonymousViews are false true', function (done) {
configMock.allowAnonymous = false
configMock.allowAnonymousEdits = true
configMock.allowAnonymousViews = true
realtime.notes[noteId].socks = [clientSocket, undefined, otherClient]
permissionFunc('editable')
setTimeout(() => {
assert(checkViewPermissionSpy.callCount === 2)
assert(otherClient.emit.called === false)
assert(otherClient.disconnect.called === false)
assert(clientSocket.emit.called === false)
assert(clientSocket.disconnect.called === false)
done()
}, 5)
})
}) })
}) })