Skip to content

Commit 0af9bfb

Browse files
authored
Merge branch 'master' into feature/disableRequestedAuthnContext-config-option
2 parents d730639 + fadc599 commit 0af9bfb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+5216
-6082
lines changed

.travis.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ env:
88

99
jobs:
1010
include:
11-
- env: task=npm-test
12-
node_js:
13-
- 6
14-
before_install:
15-
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version "$YARN_VERSION"
16-
- export PATH="$HOME/.yarn/bin:$PATH"
1711
- env: task=npm-test
1812
node_js:
1913
- 8

README.md

Lines changed: 78 additions & 356 deletions
Large diffs are not rendered by default.

app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ if (config.csp.enable) {
113113
}
114114

115115
i18n.configure({
116-
locales: ['en', 'zh-CN', 'zh-TW', 'fr', 'de', 'ja', 'es', 'ca', 'el', 'pt', 'it', 'tr', 'ru', 'nl', 'hr', 'pl', 'uk', 'hi', 'sv', 'eo', 'da', 'ko', 'id'],
116+
locales: ['en', 'zh-CN', 'zh-TW', 'fr', 'de', 'ja', 'es', 'ca', 'el', 'pt', 'it', 'tr', 'ru', 'nl', 'hr', 'pl', 'uk', 'hi', 'sv', 'eo', 'da', 'ko', 'id', 'sr'],
117117
cookie: 'locale',
118118
directory: path.join(__dirname, '/locales'),
119119
updateFiles: config.updateI18nFiles

app.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"Markdown",
77
"Notes"
88
],
9-
"website": "https://hackmd.io",
9+
"website": "https://github.com/hackmdio/codimd",
1010
"repository": "https://github.com/hackmdio/codimd",
1111
"logo": "https://github.com/hackmdio/codimd/raw/master/public/codimd-icon-1024.png",
1212
"success_url": "/",

bin/manage_users

Lines changed: 79 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,117 @@
11
#!/usr/bin/env node
22

33
// First configure the logger so it does not spam the console
4-
const logger = require("../lib/logger");
5-
logger.transports.console.level = "warning";
4+
const logger = require('../lib/logger')
5+
logger.transports.forEach((transport) => {
6+
transport.level = 'warning'
7+
})
68

7-
const models = require("../lib/models/");
8-
const readline = require("readline-sync");
9-
const minimist = require("minimist");
9+
const models = require('../lib/models/')
10+
const readline = require('readline-sync')
11+
const minimist = require('minimist')
1012

11-
function showUsage(tips) {
12-
console.log(`${tips}
13+
function showUsage (tips) {
14+
console.log(`${tips}
1315
1416
Command-line utility to create users for email-signin.
15-
1617
Usage: bin/manage_users [--pass password] (--add | --del) user-email
17-
Options:
18-
--add Add user with the specified user-email
19-
--del Delete user with specified user-email
20-
--reset Reset user password with specified user-email
21-
--pass Use password from cmdline rather than prompting
22-
`);
23-
process.exit(1);
18+
Options:
19+
--add\tAdd user with the specified user-email
20+
--del\tDelete user with specified user-email
21+
--reset\tReset user password with specified user-email
22+
--pass\tUse password from cmdline rather than prompting
23+
`)
24+
process.exit(1)
2425
}
2526

26-
function getPass(argv, action) {
27-
// Find whether we use cmdline or prompt password
28-
if(typeof argv["pass"] !== 'string') {
29-
return readline.question(`Password for ${argv[action]}:`, {hideEchoBack: true});
30-
}
31-
console.log("Using password from commandline...");
32-
return argv["pass"];
27+
function getPass (argv, action) {
28+
// Find whether we use cmdline or prompt password
29+
if (typeof argv['pass'] !== 'string') {
30+
return readline.question(`Password for ${argv[action]}:`, { hideEchoBack: true })
31+
}
32+
console.log('Using password from commandline...')
33+
return argv['pass']
3334
}
3435

3536
// Using an async function to be able to use await inside
36-
async function createUser(argv) {
37-
const existing_user = await models.User.findOne({where: {email: argv["add"]}});
38-
// Cannot create already-existing users
39-
if(existing_user != undefined) {
40-
console.log(`User with e-mail ${existing_user.email} already exists! Aborting ...`);
41-
process.exit(1);
42-
}
43-
44-
const pass = getPass(argv, "add");
45-
46-
47-
// Lets try to create, and check success
48-
const ref = await models.User.create({email: argv["add"], password: pass});
49-
if(ref == undefined) {
50-
console.log(`Could not create user with email ${argv["add"]}`);
51-
process.exit(1);
52-
} else
53-
console.log(`Created user with email ${argv["add"]}`);
37+
async function createUser (argv) {
38+
const existingUser = await models.User.findOne({ where: { email: argv['add'] } })
39+
// Cannot create already-existing users
40+
if (existingUser !== undefined) {
41+
console.log(`User with e-mail ${existingUser.email} already exists! Aborting ...`)
42+
process.exit(1)
43+
}
44+
45+
const pass = getPass(argv, 'add')
46+
47+
// Lets try to create, and check success
48+
const ref = await models.User.create({ email: argv['add'], password: pass })
49+
if (ref === undefined) {
50+
console.log(`Could not create user with email ${argv['add']}`)
51+
process.exit(1)
52+
} else { console.log(`Created user with email ${argv['add']}`) }
5453
}
5554

5655
// Using an async function to be able to use await inside
57-
async function deleteUser(argv) {
58-
// Cannot delete non-existing users
59-
const existing_user = await models.User.findOne({where: {email: argv["del"]}});
60-
if(existing_user === undefined) {
61-
console.log(`User with e-mail ${argv["del"]} does not exist, cannot delete`);
62-
process.exit(1);
63-
}
64-
65-
// Sadly .destroy() does not return any success value with all
66-
// backends. See sequelize #4124
67-
await existing_user.destroy();
68-
console.log(`Deleted user ${argv["del"]} ...`);
56+
async function deleteUser (argv) {
57+
// Cannot delete non-existing users
58+
const existingUser = await models.User.findOne({ where: { email: argv['del'] } })
59+
if (existingUser === undefined) {
60+
console.log(`User with e-mail ${argv['del']} does not exist, cannot delete`)
61+
process.exit(1)
62+
}
63+
64+
// Sadly .destroy() does not return any success value with all
65+
// backends. See sequelize #4124
66+
await existingUser.destroy()
67+
console.log(`Deleted user ${argv['del']} ...`)
6968
}
7069

71-
7270
// Using an async function to be able to use await inside
73-
async function resetUser(argv) {
74-
const existing_user = await models.User.findOne({where: {email: argv["reset"]}});
75-
// Cannot reset non-existing users
76-
if(existing_user == undefined) {
77-
console.log(`User with e-mail ${argv["reset"]} does not exist, cannot reset`);
78-
process.exit(1);
79-
}
80-
81-
const pass = getPass(argv, "reset");
82-
83-
// set password and save
84-
existing_user.password = pass;
85-
await existing_user.save();
86-
console.log(`User with email ${argv["reset"]} password has been reset`);
71+
async function resetUser (argv) {
72+
const existingUser = await models.User.findOne({ where: { email: argv['reset'] } })
73+
// Cannot reset non-existing users
74+
if (existingUser === undefined) {
75+
console.log(`User with e-mail ${argv['reset']} does not exist, cannot reset`)
76+
process.exit(1)
77+
}
78+
79+
const pass = getPass(argv, 'reset')
80+
81+
// set password and save
82+
existingUser.password = pass
83+
await existingUser.save()
84+
console.log(`User with email ${argv['reset']} password has been reset`)
8785
}
8886

8987
const options = {
90-
add: createUser,
91-
del: deleteUser,
92-
reset: resetUser,
93-
};
88+
add: createUser,
89+
del: deleteUser,
90+
reset: resetUser
91+
}
9492

9593
// Perform commandline-parsing
96-
const argv = minimist(process.argv.slice(2));
94+
const argv = minimist(process.argv.slice(2))
9795

98-
const keys = Object.keys(options);
99-
const opts = keys.filter((key) => argv[key] !== undefined);
100-
const action = opts[0];
96+
const keys = Object.keys(options)
97+
const opts = keys.filter((key) => argv[key] !== undefined)
98+
const action = opts[0]
10199

102100
// Check for options missing
103101
if (opts.length === 0) {
104-
showUsage(`You did not specify either ${keys.map((key) => `--${key}`).join(' or ')}!`);
102+
showUsage(`You did not specify either ${keys.map((key) => `--${key}`).join(' or ')}!`)
105103
}
106104

107105
// Check if both are specified
108106
if (opts.length > 1) {
109-
showUsage(`You cannot ${action.join(' and ')} at the same time!`);
107+
showUsage(`You cannot ${action.join(' and ')} at the same time!`)
110108
}
111109
// Check if not string
112110
if (typeof argv[action] !== 'string') {
113-
showUsage(`You must follow an email after --${action}`);
111+
showUsage(`You must follow an email after --${action}`)
114112
}
115113

116114
// Call respective processing functions
117-
options[action](argv).then(function() {
118-
process.exit(0);
119-
});
115+
options[action](argv).then(function () {
116+
process.exit(0)
117+
})

config.json.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"loglevel": "info",
2121
"hsts": {
2222
"enable": true,
23-
"maxAgeSeconds": "31536000",
23+
"maxAgeSeconds": 31536000,
2424
"includeSubdomains": true,
2525
"preload": true
2626
},

docs/guides/auth/saml.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ Authentication guide - SAML
55

66
The basic procedure is the same as the case of OneLogin which is mentioned in [OneLogin-Guide](./saml-onelogin.md). If you want to match your IdP, you can use more configurations as below.
77

8-
* If your IdP accepts metadata XML of the service provider to ease configuraion, use this url to download metadata XML.
8+
* If your IdP accepts metadata XML of the service provider to ease configuration, use this url to download metadata XML.
99
* {{your-serverurl}}/auth/saml/metadata
10-
* _Note: If not accessable from IdP, download to local once and upload to IdP._
10+
* _Note: If not accessible from IdP, download to local once and upload to IdP._
1111
* Change the value of `issuer`, `identifierFormat` to match your IdP.
1212
* `issuer`: A unique id to identify the application to the IdP, which is the base URL of your HackMD as default
1313
* `identifierFormat`: A format of unique id to identify the user of IdP, which is the format based on email address as default. It is recommend that you use as below.
@@ -59,7 +59,7 @@ The basic procedure is the same as the case of OneLogin which is mentioned in [O
5959
HMD_SAML_ATTRIBUTE_EMAIL=mail
6060
````
6161

62-
* If you want to controll permission by group membership, add group attribute name and required group (allowed) or external group (not allowed).
62+
* If you want to control permission by group membership, add group attribute name and required group (allowed) or external group (not allowed).
6363
* `groupAttribute`: An attribute name of group membership
6464
* `requiredGroups`: Group names array for allowed access to HackMD. Use vertical bar to separate for environment variables.
6565
* `externalGroups`: Group names array for not allowed access to HackMD. Use vertical bar to separate for environment variables.

lib/config/default.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ module.exports = {
5656
// socket.io
5757
heartbeatInterval: 5000,
5858
heartbeatTimeout: 10000,
59+
// toobusy-js
60+
responseMaxLag: 70,
5961
// document
6062
documentMaxLength: 100000,
6163
// image upload setting, available options are imgur/s3/filesystem/azure
@@ -66,7 +68,8 @@ module.exports = {
6668
s3: {
6769
accessKeyId: undefined,
6870
secretAccessKey: undefined,
69-
region: undefined
71+
region: undefined,
72+
endpoint: undefined
7073
},
7174
minio: {
7275
accessKey: undefined,
@@ -152,5 +155,5 @@ module.exports = {
152155
allowEmailRegister: true,
153156
allowGravatar: true,
154157
allowPDFExport: true,
155-
openID: true
158+
openID: false
156159
}

lib/config/environment.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const {toBooleanConfig, toArrayConfig, toIntegerConfig} = require('./utils')
3+
const { toBooleanConfig, toArrayConfig, toIntegerConfig } = require('./utils')
44

55
module.exports = {
66
sourceURL: process.env.CMD_SOURCE_URL,
@@ -14,7 +14,7 @@ module.exports = {
1414
useSSL: toBooleanConfig(process.env.CMD_USESSL),
1515
hsts: {
1616
enable: toBooleanConfig(process.env.CMD_HSTS_ENABLE),
17-
maxAgeSeconds: process.env.CMD_HSTS_MAX_AGE,
17+
maxAgeSeconds: toIntegerConfig(process.env.CMD_HSTS_MAX_AGE),
1818
includeSubdomains: toBooleanConfig(process.env.CMD_HSTS_INCLUDE_SUBDOMAINS),
1919
preload: toBooleanConfig(process.env.CMD_HSTS_PRELOAD)
2020
},
@@ -33,14 +33,16 @@ module.exports = {
3333
dbURL: process.env.CMD_DB_URL,
3434
sessionSecret: process.env.CMD_SESSION_SECRET,
3535
sessionLife: toIntegerConfig(process.env.CMD_SESSION_LIFE),
36+
responseMaxLag: toIntegerConfig(process.env.CMD_RESPONSE_MAX_LAG),
3637
imageUploadType: process.env.CMD_IMAGE_UPLOAD_TYPE,
3738
imgur: {
3839
clientID: process.env.CMD_IMGUR_CLIENTID
3940
},
4041
s3: {
4142
accessKeyId: process.env.CMD_S3_ACCESS_KEY_ID,
4243
secretAccessKey: process.env.CMD_S3_SECRET_ACCESS_KEY,
43-
region: process.env.CMD_S3_REGION
44+
region: process.env.CMD_S3_REGION,
45+
endpoint: process.env.CMD_S3_ENDPOINT
4446
},
4547
minio: {
4648
accessKey: process.env.CMD_MINIO_ACCESS_KEY,

lib/config/hackmdEnvironment.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const {toBooleanConfig, toArrayConfig, toIntegerConfig} = require('./utils')
3+
const { toBooleanConfig, toArrayConfig, toIntegerConfig } = require('./utils')
44

55
module.exports = {
66
domain: process.env.HMD_DOMAIN,
@@ -10,7 +10,7 @@ module.exports = {
1010
useSSL: toBooleanConfig(process.env.HMD_USESSL),
1111
hsts: {
1212
enable: toBooleanConfig(process.env.HMD_HSTS_ENABLE),
13-
maxAgeSeconds: process.env.HMD_HSTS_MAX_AGE,
13+
maxAgeSeconds: toIntegerConfig(process.env.HMD_HSTS_MAX_AGE),
1414
includeSubdomains: toBooleanConfig(process.env.HMD_HSTS_INCLUDE_SUBDOMAINS),
1515
preload: toBooleanConfig(process.env.HMD_HSTS_PRELOAD)
1616
},
@@ -28,6 +28,7 @@ module.exports = {
2828
dbURL: process.env.HMD_DB_URL,
2929
sessionSecret: process.env.HMD_SESSION_SECRET,
3030
sessionLife: toIntegerConfig(process.env.HMD_SESSION_LIFE),
31+
responseMaxLag: toIntegerConfig(process.env.HMD_RESPONSE_MAX_LAG),
3132
imageUploadType: process.env.HMD_IMAGE_UPLOAD_TYPE,
3233
imgur: {
3334
clientID: process.env.HMD_IMGUR_CLIENTID

0 commit comments

Comments
 (0)