summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--config.json.example4
-rw-r--r--lib/config/index.js2
-rw-r--r--lib/letter-avatars.js17
-rw-r--r--lib/models/note.js9
-rw-r--r--lib/models/user.js10
-rw-r--r--lib/realtime.js2
-rw-r--r--lib/response.js4
-rw-r--r--lib/web/auth/saml/index.js4
-rw-r--r--lib/web/userRouter.js7
-rw-r--r--package.json3
-rw-r--r--webpackBaseConfig.js5
-rw-r--r--yarn.lock2
13 files changed, 49 insertions, 23 deletions
diff --git a/README.md b/README.md
index 5ab6c849..4f5a4b41 100644
--- a/README.md
+++ b/README.md
@@ -60,7 +60,6 @@ Thanks for using! :smile:
- Database (PostgreSQL, MySQL, MariaDB, SQLite, MSSQL) use charset `utf8`
- npm (and its dependencies, especially [uWebSockets](https://github.com/uWebSockets/uWebSockets#nodejs-developers), [node-gyp](https://github.com/nodejs/node-gyp#installation))
- For **building** HackMD we recommend to use a machine with at least **2GB** RAM
-- (optional) *For development you may need to increase the number of allowed open file descriptors on your machine*
### Instructions
@@ -329,5 +328,5 @@ See more at [http://operational-transformation.github.io/](http://operational-tr
[standardjs-url]: https://github.com/feross/standard
[codetriage-image]: https://www.codetriage.com/hackmdio/hackmd/badges/users.svg
[codetriage-url]: https://www.codetriage.com/hackmdio/hackmd
-[poeditor-image]: https://img.shields.io/badge/POEditor-translate-green.svg
+[poeditor-image]: https://img.shields.io/badge/POEditor-translate-blue.svg
[poeditor-url]: https://poeditor.com/join/project/1OpGjF2Jir
diff --git a/config.json.example b/config.json.example
index 2d9b7714..6cd55efb 100644
--- a/config.json.example
+++ b/config.json.example
@@ -22,11 +22,11 @@
"includeSubdomains": true,
"preload": true
},
- csp: {
+ "csp": {
"enable": true,
"directives": {
},
- "upgradeInsecureRequests": "auto"
+ "upgradeInsecureRequests": "auto",
"addDefaults": true,
"addDisqus": true,
"addGoogleAnalytics": true
diff --git a/lib/config/index.js b/lib/config/index.js
index d885ee92..bdba5e0e 100644
--- a/lib/config/index.js
+++ b/lib/config/index.js
@@ -53,7 +53,7 @@ if (config.ldap.tlsca) {
// Permission
config.permission = Permission
-if (!config.allowAnonymous && !config.allowAnonymousedits) {
+if (!config.allowAnonymous && !config.allowAnonymousEdits) {
delete config.permission.freely
}
if (!(config.defaultPermission in config.permission)) {
diff --git a/lib/letter-avatars.js b/lib/letter-avatars.js
index 7ba336b6..b5b1d9e7 100644
--- a/lib/letter-avatars.js
+++ b/lib/letter-avatars.js
@@ -1,16 +1,17 @@
'use strict'
// external modules
-var randomcolor = require('randomcolor')
+const randomcolor = require('randomcolor')
+const config = require('./config')
// core
-module.exports = function (name) {
- var color = randomcolor({
+exports.generateAvatar = function (name) {
+ const color = randomcolor({
seed: name,
luminosity: 'dark'
})
- var letter = name.substring(0, 1).toUpperCase()
+ const letter = name.substring(0, 1).toUpperCase()
- var svg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
+ let svg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
svg += '<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="96" width="96" version="1.1" viewBox="0 0 96 96">'
svg += '<g>'
svg += '<rect width="96" height="96" fill="' + color + '" />'
@@ -20,5 +21,9 @@ module.exports = function (name) {
svg += '</g>'
svg += '</svg>'
- return 'data:image/svg+xml;base64,' + new Buffer(svg).toString('base64')
+ return svg
+}
+
+exports.generateAvatarURL = function (name) {
+ return config.serverURL + '/user/' + name + '/avatar.svg'
}
diff --git a/lib/models/note.js b/lib/models/note.js
index 69393dd4..2a048e37 100644
--- a/lib/models/note.js
+++ b/lib/models/note.js
@@ -211,6 +211,15 @@ module.exports = function (sequelize, DataTypes) {
},
// parse note id by LZString is deprecated, here for compability
parseNoteIdByLZString: function (_callback) {
+ // Calculate minimal string length for an UUID that is encoded
+ // base64 encoded and optimize comparsion by using -1
+ // this should make a lot of LZ-String parsing errors obsolete
+ // as we can assume that a nodeId that is 48 chars or longer is a
+ // noteID.
+ const base64UuidLength = ((4 * 36) / 3) - 1
+ if (!(noteId.length > base64UuidLength)) {
+ return _callback(null, null)
+ }
// try to parse note id by LZString Base64
try {
var id = LZString.decompressFromBase64(noteId)
diff --git a/lib/models/user.js b/lib/models/user.js
index f421fe43..4c823355 100644
--- a/lib/models/user.js
+++ b/lib/models/user.js
@@ -6,7 +6,7 @@ var scrypt = require('scrypt')
// core
var logger = require('../logger')
-var letterAvatars = require('../letter-avatars')
+var {generateAvatarURL} = require('../letter-avatars')
module.exports = function (sequelize, DataTypes) {
var User = sequelize.define('User', {
@@ -108,7 +108,7 @@ module.exports = function (sequelize, DataTypes) {
if (bigger) photo = photo.replace(/(\?s=)\d*$/i, '$1400')
else photo = photo.replace(/(\?s=)\d*$/i, '$196')
} else {
- photo = letterAvatars(profile.username)
+ photo = generateAvatarURL(profile.username)
}
break
case 'mattermost':
@@ -117,7 +117,7 @@ module.exports = function (sequelize, DataTypes) {
if (bigger) photo = photo.replace(/(\?s=)\d*$/i, '$1400')
else photo = photo.replace(/(\?s=)\d*$/i, '$196')
} else {
- photo = letterAvatars(profile.username)
+ photo = generateAvatarURL(profile.username)
}
break
case 'dropbox':
@@ -140,7 +140,7 @@ module.exports = function (sequelize, DataTypes) {
if (bigger) photo += '?s=400'
else photo += '?s=96'
} else {
- photo = letterAvatars(profile.username)
+ photo = generateAvatarURL(profile.username)
}
break
case 'saml':
@@ -149,7 +149,7 @@ module.exports = function (sequelize, DataTypes) {
if (bigger) photo += '?s=400'
else photo += '?s=96'
} else {
- photo = letterAvatars(profile.username)
+ photo = generateAvatarURL(profile.username)
}
break
}
diff --git a/lib/realtime.js b/lib/realtime.js
index d8b0b4c5..070bde2d 100644
--- a/lib/realtime.js
+++ b/lib/realtime.js
@@ -788,7 +788,7 @@ function connection (socket) {
var note = notes[noteId]
// Only owner can change permission
if (note.owner && note.owner === socket.request.user.id) {
- if (permission === 'freely' && !config.allowAnonymous && !config.allowAnonymousedits) return
+ if (permission === 'freely' && !config.allowAnonymous && !config.allowAnonymousEdits) return
note.permission = permission
models.Note.update({
permission: permission
diff --git a/lib/response.js b/lib/response.js
index d5c685ca..ae3e45fa 100644
--- a/lib/response.js
+++ b/lib/response.js
@@ -59,7 +59,7 @@ function showIndex (req, res, next) {
url: config.serverURL,
useCDN: config.useCDN,
allowAnonymous: config.allowAnonymous,
- allowAnonymousEdits: config.allowAnonymousedits,
+ allowAnonymousEdits: config.allowAnonymousEdits,
facebook: config.isFacebookEnable,
twitter: config.isTwitterEnable,
github: config.isGitHubEnable,
@@ -94,7 +94,7 @@ function responseHackMD (res, note) {
title: title,
useCDN: config.useCDN,
allowAnonymous: config.allowAnonymous,
- allowAnonymousEdits: config.allowAnonymousedits,
+ allowAnonymousEdits: config.allowAnonymousEdits,
facebook: config.isFacebookEnable,
twitter: config.isTwitterEnable,
github: config.isGitHubEnable,
diff --git a/lib/web/auth/saml/index.js b/lib/web/auth/saml/index.js
index 3ecbc6f3..b8d98340 100644
--- a/lib/web/auth/saml/index.js
+++ b/lib/web/auth/saml/index.js
@@ -20,14 +20,14 @@ passport.use(new SamlStrategy({
identifierFormat: config.saml.identifierFormat
}, function (user, done) {
// check authorization if needed
- if (config.saml.externalGroups && config.saml.grouptAttribute) {
+ if (config.saml.externalGroups && config.saml.groupAttribute) {
var externalGroups = intersection(config.saml.externalGroups, user[config.saml.groupAttribute])
if (externalGroups.length > 0) {
logger.error('saml permission denied: ' + externalGroups.join(', '))
return done('Permission denied', null)
}
}
- if (config.saml.requiredGroups && config.saml.grouptAttribute) {
+ if (config.saml.requiredGroups && config.saml.groupAttribute) {
if (intersection(config.saml.requiredGroups, user[config.saml.groupAttribute]).length === 0) {
logger.error('saml permission denied')
return done('Permission denied', null)
diff --git a/lib/web/userRouter.js b/lib/web/userRouter.js
index ecfbaf8b..963961c7 100644
--- a/lib/web/userRouter.js
+++ b/lib/web/userRouter.js
@@ -5,6 +5,7 @@ const Router = require('express').Router
const response = require('../response')
const models = require('../models')
const logger = require('../logger')
+const {generateAvatar} = require('../letter-avatars')
const UserRouter = module.exports = Router()
@@ -34,3 +35,9 @@ UserRouter.get('/me', function (req, res) {
})
}
})
+
+UserRouter.get('/user/:username/avatar.svg', function (req, res, next) {
+ res.setHeader('Content-Type', 'image/svg+xml')
+ res.setHeader('Cache-Control', 'public, max-age=86400')
+ res.send(generateAvatar(req.params.username))
+})
diff --git a/package.json b/package.json
index 6cf495c9..43eb9250 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"license": "AGPL-3.0",
"scripts": {
"test": "npm run-script standard && npm run-script jsonlint",
- "jsonlint": "find . -not -path './node_modules/*' -type f -name '*.json' | while read json; do echo $json ; jq . $json; done",
+ "jsonlint": "find . -not -path './node_modules/*' -type f -name '*.json' -o -type f -name '*.json.example' | while read json; do echo $json ; jq . $json; done",
"standard": "node ./node_modules/standard/bin/cmd.js",
"dev": "webpack --config webpack.config.js --progress --colors --watch",
"build": "webpack --config webpack.production.js --progress --colors --bail",
@@ -42,6 +42,7 @@
"font-awesome": "^4.7.0",
"formidable": "^1.0.17",
"gist-embed": "~2.6.0",
+ "graceful-fs": "^4.1.11",
"handlebars": "^4.0.6",
"helmet": "^3.3.0",
"highlight.js": "~9.9.0",
diff --git a/webpackBaseConfig.js b/webpackBaseConfig.js
index e8630841..793308ea 100644
--- a/webpackBaseConfig.js
+++ b/webpackBaseConfig.js
@@ -4,6 +4,11 @@ var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var CopyWebpackPlugin = require('copy-webpack-plugin')
+// Fix possible nofile-issues
+var fs = require('fs')
+var gracefulFs = require('graceful-fs')
+gracefulFs.gracefulify(fs)
+
module.exports = {
plugins: [
new webpack.ProvidePlugin({
diff --git a/yarn.lock b/yarn.lock
index 3246fa99..2c906935 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2968,7 +2968,7 @@ good-listener@^1.2.2:
dependencies:
delegate "^3.1.2"
-graceful-fs@*, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
+graceful-fs@*, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"