Unverified Commit a0cc1955 authored by Max Wu's avatar Max Wu Committed by GitHub
Browse files

Prepare release 1.4.0 (#1344)

Prepare release 1.4.0
parents 5256fe98 2358dd2f
.idea
coverage
node_modules/
# ignore config files
config.json
.sequelizerc
# ignore webpack build
public/build
public/views/build
.nyc_output
coverage/
lib/ot
public/vendor
public/build
module.exports = {
"root": true,
"extends": "standard",
"env": {
"node": true
},
"rules": {
// at some point all of these should return to their default "error" state
// but right now, this is not a good choice, because too many places are
// wrong.
"import/first": ["warn"],
"indent": ["warn"],
"no-multiple-empty-lines": ["warn"],
"no-multi-spaces": ["warn"],
"object-curly-spacing": ["warn"],
"one-var": ["warn"],
"quotes": ["warn"],
"semi": ["warn"],
"space-infix-ops": ["warn"]
}
};
...@@ -27,3 +27,5 @@ public/views/build ...@@ -27,3 +27,5 @@ public/views/build
public/uploads/* public/uploads/*
!public/uploads/.gitkeep !public/uploads/.gitkeep
/.nyc_output
/coverage/
var path = require('path'); const path = require('path')
const config = require('./lib/config')
module.exports = { module.exports = {
'config': path.resolve('config.json'), config: path.resolve('config.json'),
'migrations-path': path.resolve('lib', 'migrations'), 'migrations-path': path.resolve('lib', 'migrations'),
'models-path': path.resolve('lib', 'models'), 'models-path': path.resolve('lib', 'models'),
'url': 'change this' url: process.env['CMD_DB_URL'] || config.dbURL
} }
\ No newline at end of file
language: node_js language: node_js
dist: trusty
node_js:
- "lts/carbon"
- "lts/dubnium"
- "11"
- "12"
dist: xenial
cache: yarn cache: yarn
env:
global: matrix:
- CXX=g++-4.8 fast_finish: true
- YARN_VERSION=1.3.2 include:
- node_js: lts/carbon
- node_js: lts/dubnium
allow_failures:
- node_js: "11"
- node_js: "12"
script:
- yarn test:ci
- yarn build
jobs: jobs:
include: include:
- env: task=npm-test - stage: doctoc-check
node_js: install: npm install -g doctoc
- 8 if: type = pull_request OR branch = master
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version "$YARN_VERSION"
- export PATH="$HOME/.yarn/bin:$PATH"
- env: task=npm-test
node_js:
- 10
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version "$YARN_VERSION"
- export PATH="$HOME/.yarn/bin:$PATH"
- env: task=ShellCheck
script:
- shellcheck bin/heroku bin/setup
language: generic
- env: task=doctoc
install: npm install doctoc
script: script:
- cp README.md README.md.orig - cp README.md README.md.orig
- npm run doctoc - npm run doctoc
- diff -q README.md README.md.orig - diff -q README.md README.md.orig
language: generic node_js: lts/carbon
- env: task=json-lint
addons:
apt:
packages:
- jq
script:
- npm run jsonlint
language: generic
...@@ -9,6 +9,8 @@ CodiMD ...@@ -9,6 +9,8 @@ CodiMD
CodiMD lets you collaborate in real-time with markdown. CodiMD lets you collaborate in real-time with markdown.
Built on [HackMD](https://hackmd.io) source code, CodiMD lets you host and control your team's content with speed and ease. Built on [HackMD](https://hackmd.io) source code, CodiMD lets you host and control your team's content with speed and ease.
![screenshot](https://raw.githubusercontent.com/hackmdio/codimd/develop/public/screenshot.png)
<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
# Table of Contents # Table of Contents
...@@ -71,20 +73,11 @@ All contributions are welcome! Even asking a question helps. ...@@ -71,20 +73,11 @@ All contributions are welcome! Even asking a question helps.
## Browser Support ## Browser Support
CodiMD is a service that runs on Node.js, while users use the service through browsers. We support your users using the following browsers: CodiMD is a service that runs on Node.js, while users use the service through browsers. We support your users using the following browsers:
- ![Chrome](http://browserbadge.com/chrome/47/18px) - <img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" /> Chrome >= 47, Chrome for Android >= 47
- Chrome >= 47 - <img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" /> Safari >= 9, iOS Safari >= 8.4
- Chrome for Android >= 47 - <img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" /> Firefox >= 44
- ![Safari](http://browserbadge.com/safari/9/18px) - <img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" /> IE >= 9, Edge >= 12
- Safari >= 9 - <img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" /> Opera >= 34, Opera Mini not supported
- iOS Safari >= 8.4
- ![Firefox](http://browserbadge.com/firefox/44/18px)
- Firefox >= 44
- ![IE](http://browserbadge.com/ie/9/18px)
- IE >= 9
- Edge >= 12
- ![Opera](http://browserbadge.com/opera/34/18px)
- Opera >= 34
- Opera Mini not supported
- Android Browser >= 4.4 - Android Browser >= 4.4
To stay up to date with your installation it's recommended to subscribe the [release feed][github-release-feed]. To stay up to date with your installation it's recommended to subscribe the [release feed][github-release-feed].
......
...@@ -7,7 +7,6 @@ var ejs = require('ejs') ...@@ -7,7 +7,6 @@ var ejs = require('ejs')
var passport = require('passport') var passport = require('passport')
var methodOverride = require('method-override') var methodOverride = require('method-override')
var cookieParser = require('cookie-parser') var cookieParser = require('cookie-parser')
var compression = require('compression')
var session = require('express-session') var session = require('express-session')
var SequelizeStore = require('connect-session-sequelize')(session.Store) var SequelizeStore = require('connect-session-sequelize')(session.Store)
var fs = require('fs') var fs = require('fs')
...@@ -26,34 +25,37 @@ var response = require('./lib/response') ...@@ -26,34 +25,37 @@ var response = require('./lib/response')
var models = require('./lib/models') var models = require('./lib/models')
var csp = require('./lib/csp') var csp = require('./lib/csp')
// server setup function createHttpServer () {
var app = express() if (config.useSSL) {
var server = null const ca = (function () {
if (config.useSSL) { let i, len
var ca = (function () { const results = []
var i, len, results for (i = 0, len = config.sslCAPath.length; i < len; i++) {
results = [] results.push(fs.readFileSync(config.sslCAPath[i], 'utf8'))
for (i = 0, len = config.sslCAPath.length; i < len; i++) { }
results.push(fs.readFileSync(config.sslCAPath[i], 'utf8')) return results
})()
const options = {
key: fs.readFileSync(config.sslKeyPath, 'utf8'),
cert: fs.readFileSync(config.sslCertPath, 'utf8'),
ca: ca,
dhparam: fs.readFileSync(config.dhParamPath, 'utf8'),
requestCert: false,
rejectUnauthorized: false
} }
return results return require('https').createServer(options, app)
})() } else {
var options = { return require('http').createServer(app)
key: fs.readFileSync(config.sslKeyPath, 'utf8'),
cert: fs.readFileSync(config.sslCertPath, 'utf8'),
ca: ca,
dhparam: fs.readFileSync(config.dhParamPath, 'utf8'),
requestCert: false,
rejectUnauthorized: false
} }
server = require('https').createServer(options, app)
} else {
server = require('http').createServer(app)
} }
// server setup
var app = express()
var server = createHttpServer()
// logger // logger
app.use(morgan('combined', { app.use(morgan('combined', {
'stream': logger.stream stream: logger.stream
})) }))
// socket io // socket io
...@@ -77,9 +79,6 @@ var sessionStore = new SequelizeStore({ ...@@ -77,9 +79,6 @@ var sessionStore = new SequelizeStore({
db: models.sequelize db: models.sequelize
}) })
// compression
app.use(compression())
// use hsts to tell https users stick to this // use hsts to tell https users stick to this
if (config.hsts.enable) { if (config.hsts.enable) {
app.use(helmet.hsts({ app.use(helmet.hsts({
...@@ -181,6 +180,7 @@ app.locals.serverURL = config.serverURL ...@@ -181,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,
...@@ -279,6 +279,7 @@ process.on('uncaughtException', function (err) { ...@@ -279,6 +279,7 @@ process.on('uncaughtException', function (err) {
function handleTermSignals () { function handleTermSignals () {
logger.info('CodiMD has been killed by signal, try to exit gracefully...') logger.info('CodiMD has been killed by signal, try to exit gracefully...')
realtime.maintenance = true realtime.maintenance = true
realtime.terminate()
// disconnect all socket.io clients // disconnect all socket.io clients
Object.keys(io.sockets.sockets).forEach(function (key) { Object.keys(io.sockets.sockets).forEach(function (key) {
var socket = io.sockets.sockets[key] var socket = io.sockets.sockets[key]
...@@ -299,6 +300,9 @@ function handleTermSignals () { ...@@ -299,6 +300,9 @@ function handleTermSignals () {
}) })
} }
}, 100) }, 100)
setTimeout(() => {
process.exit(1)
}, 5000)
} }
process.on('SIGINT', handleTermSignals) process.on('SIGINT', handleTermSignals)
process.on('SIGTERM', handleTermSignals) process.on('SIGTERM', handleTermSignals)
......
...@@ -11,18 +11,10 @@ ...@@ -11,18 +11,10 @@
"logo": "https://github.com/hackmdio/codimd/raw/master/public/codimd-icon-1024.png", "logo": "https://github.com/hackmdio/codimd/raw/master/public/codimd-icon-1024.png",
"success_url": "/", "success_url": "/",
"env": { "env": {
"BUILD_ASSETS": {
"description": "Our build script variable",
"value": "true"
},
"NPM_CONFIG_PRODUCTION": { "NPM_CONFIG_PRODUCTION": {
"description": "Let npm also install development build tool", "description": "Let npm also install development build tool",
"value": "false" "value": "false"
}, },
"DB_TYPE": {
"description": "Specify database type. See sequelize available databases. Default using postgres",
"value": "postgres"
},
"HMD_SESSION_SECRET": { "HMD_SESSION_SECRET": {
"description": "Secret used to secure session cookies.", "description": "Secret used to secure session cookies.",
"required": false "required": false
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
set -e set -e
if [ "$BUILD_ASSETS" = true ]; then if [ ! -z "$DYNO" ]; then
# setup config files # setup config files
cat << EOF > .sequelizerc cat << EOF > .sequelizerc
var path = require('path'); var path = require('path');
...@@ -11,8 +11,7 @@ module.exports = { ...@@ -11,8 +11,7 @@ module.exports = {
'config': path.resolve('config.json'), 'config': path.resolve('config.json'),
'migrations-path': path.resolve('lib', 'migrations'), 'migrations-path': path.resolve('lib', 'migrations'),
'models-path': path.resolve('lib', 'models'), 'models-path': path.resolve('lib', 'models'),
'url': process.env.DATABASE_URL, 'url': process.env.DATABASE_URL
'dialect': process.env.DB_TYPE
} }
EOF EOF
...@@ -26,6 +25,4 @@ EOF ...@@ -26,6 +25,4 @@ EOF
EOF EOF
# build app
npm run build
fi fi
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
"db": { "db": {
"dialect": "sqlite", "dialect": "sqlite",
"storage": ":memory:" "storage": ":memory:"
} },
"linkifyHeaderStyle": "gfm"
}, },
"development": { "development": {
"loglevel": "debug", "loglevel": "debug",
...@@ -13,7 +14,8 @@ ...@@ -13,7 +14,8 @@
"db": { "db": {
"dialect": "sqlite", "dialect": "sqlite",
"storage": "./db.codimd.sqlite" "storage": "./db.codimd.sqlite"
} },
"linkifyHeaderStyle": "gfm"
}, },
"production": { "production": {
"domain": "localhost", "domain": "localhost",
...@@ -123,6 +125,11 @@ ...@@ -123,6 +125,11 @@
{ {
"connectionString": "change this", "connectionString": "change this",
"container": "change this" "container": "change this"
} },
"plantuml":
{
"server": "https://www.plantuml.com/plantuml"
},
"linkifyHeaderStyle": "gfm"
} }
} }
FROM hackmdio/buildpack:1.0.4 as BUILD
COPY --chown=hackmd:hackmd . .
RUN set -xe && \
git reset --hard && \
git clean -fx && \
yarn install && \
yarn build && \
yarn install --production=true && \
cp ./deployments/docker-entrypoint.sh ./ && \
cp .sequelizerc.example .sequelizerc && \
rm -rf .git .gitignore .travis.yml .dockerignore .editorconfig .babelrc .mailmap .sequelizerc.example \
test docs contribute \
yarn.lock webpack.prod.js webpack.htmlexport.js webpack.dev.js webpack.common.js \
config.json.example README.md CONTRIBUTING.md AUTHORS
FROM hackmdio/runtime:1.0.4
USER hackmd
WORKDIR /home/hackmd/app
COPY --chown=1500:1500 --from=BUILD /home/hackmd/app .
EXPOSE 3000
ENTRYPOINT ["/home/hackmd/app/docker-entrypoint.sh"]
#!/usr/bin/env bash
CURRENT_DIR=$(dirname "$BASH_SOURCE")
docker build -t hackmdio/codimd -f "$CURRENT_DIR/Dockerfile" "$CURRENT_DIR/.."
version: "3"
services:
database:
image: postgres:11.5
environment:
- POSTGRES_USER=codimd
- POSTGRES_PASSWORD=change_password
- POSTGRES_DB=codimd
volumes:
- "database-data:/var/lib/postgresql/data"
restart: always
codimd:
build:
context: ..
dockerfile: ./deployments/Dockerfile
environment:
- CMD_DB_URL=postgres://codimd:change_password@database/codimd
- CMD_USECDN=false
depends_on:
- database
ports:
- "3000:3000"
volumes:
- upload-data:/home/hackmd/app/public/uploads
restart: always
volumes:
database-data: {}
upload-data: {}
#!/usr/bin/env bash
set -euo pipefail
if [[ "$#" -gt 0 ]]; then
exec "$@"
exit $?
fi
# check database and redis is ready
pcheck -constr "$CMD_DB_URL"
# run DB migrate
NEED_MIGRATE=${CMD_AUTO_MIGRATE:=true}
if [[ "$NEED_MIGRATE" = "true" ]] && [[ -f .sequelizerc ]] ; then
npx sequelize db:migrate
fi
# start application
node app.js
...@@ -31,6 +31,7 @@ module.exports = { ...@@ -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',
...@@ -60,8 +61,11 @@ module.exports = { ...@@ -60,8 +61,11 @@ module.exports = {
responseMaxLag: 70, responseMaxLag: 70,
// document // document
documentMaxLength: 100000, documentMaxLength: 100000,
// image upload setting, available options are imgur/s3/filesystem/azure // image upload setting, available options are imgur/s3/filesystem/azure/lutim
imageUploadType: 'filesystem', imageUploadType: 'filesystem',
lutim: {
url: 'https://framapic.org/'
},
imgur: { imgur: {
clientID: undefined clientID: undefined
}, },
...@@ -100,6 +104,7 @@ module.exports = { ...@@ -100,6 +104,7 @@ module.exports = {
consumerSecret: undefined consumerSecret: undefined
}, },
github: { github: {
enterpriseURL: undefined, // if you use github.com, not need to specify
clientID: undefined, clientID: undefined,
clientSecret: undefined clientSecret: undefined
}, },
...@@ -151,9 +156,27 @@ module.exports = { ...@@ -151,9 +156,27 @@ module.exports = {
email: undefined email: undefined
} }
}, },
plantuml: {
server: 'https://www.plantuml.com/plantuml'
},
email: true, email: true,
allowEmailRegister: true, allowEmailRegister: true,
allowGravatar: true, allowGravatar: true,
allowPDFExport: true, allowPDFExport: true,
openID: false openID: false,
defaultUseHardbreak: true,
// linkifyHeaderStyle - How is a header text converted into a link id.
// Header Example: "3.1. Good Morning my Friend! - Do you have 5$?"
// * 'keep-case' is the legacy CodiMD value.
// Generated id: "31-Good-Morning-my-Friend---Do-you-have-5"
// * 'lower-case' is the same like legacy (see above), but converted to lower-case.
// Generated id: "#31-good-morning-my-friend---do-you-have-5"
// * 'gfm' _GitHub-Flavored Markdown_ style as described here:
// https://gist.github.com/asabaylus/3071099#gistcomment-1593627
// It works like 'lower-case', but making sure the ID is unique.
// This is What GitHub, GitLab and (hopefully) most other tools use.
// Generated id: "31-good-morning-my-friend---do-you-have-5"
// 2nd appearance: "31-good-morning-my-friend---do-you-have-5-1"
// 3rd appearance: "31-good-morning-my-friend---do-you-have-5-2"
linkifyHeaderStyle: 'keep-case'
} }
...@@ -27,6 +27,7 @@ module.exports = { ...@@ -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,
...@@ -65,6 +66,7 @@ module.exports = { ...@@ -65,6 +66,7 @@ module.exports = {
consumerSecret: process.env.CMD_TWITTER_CONSUMERSECRET consumerSecret: process.env.CMD_TWITTER_CONSUMERSECRET
}, },
github: { github: {
enterpriseURL: process.env.CMD_GITHUB_ENTERPRISE_URL,
clientID: process.env.CMD_GITHUB_CLIENTID, clientID: process.env.CMD_GITHUB_CLIENTID,
clientSecret: process.env.CMD_GITHUB_CLIENTSECRET clientSecret: process.env.CMD_GITHUB_CLIENTSECRET
}, },
...@@ -127,9 +129,14 @@ module.exports = { ...@@ -127,9 +129,14 @@ module.exports = {
email: process.env.CMD_SAML_ATTRIBUTE_EMAIL email: process.env.CMD_SAML_ATTRIBUTE_EMAIL
} }
}, },
plantuml: {
server: process.env.CMD_PLANTUML_SERVER
},
email: toBooleanConfig(process.env.CMD_EMAIL), email: toBooleanConfig(process.env.CMD_EMAIL),
allowEmailRegister: toBooleanConfig(process.env.CMD_ALLOW_EMAIL_REGISTER),