Merge branch 'master' into DepauMD
This commit is contained in:
commit
550f6ebb1f
19 changed files with 92 additions and 23 deletions
|
@ -16,7 +16,7 @@ jobs:
|
||||||
- export PATH="$HOME/.yarn/bin:$PATH"
|
- export PATH="$HOME/.yarn/bin:$PATH"
|
||||||
- env: task=npm-test
|
- env: task=npm-test
|
||||||
node_js:
|
node_js:
|
||||||
- 7
|
- 8
|
||||||
before_install:
|
before_install:
|
||||||
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version "$YARN_VERSION"
|
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version "$YARN_VERSION"
|
||||||
- export PATH="$HOME/.yarn/bin:$PATH"
|
- export PATH="$HOME/.yarn/bin:$PATH"
|
||||||
|
|
17
README.md
17
README.md
|
@ -29,6 +29,7 @@ Thanks for using! :smile:
|
||||||
- [Heroku Deployment](#heroku-deployment)
|
- [Heroku Deployment](#heroku-deployment)
|
||||||
- [Kubernetes](#kubernetes)
|
- [Kubernetes](#kubernetes)
|
||||||
- [CodiMD by docker container](#codimd-by-docker-container)
|
- [CodiMD by docker container](#codimd-by-docker-container)
|
||||||
|
- [Cloudron](#cloudron)
|
||||||
- [Upgrade](#upgrade)
|
- [Upgrade](#upgrade)
|
||||||
- [Native setup](#native-setup)
|
- [Native setup](#native-setup)
|
||||||
- [Configuration](#configuration)
|
- [Configuration](#configuration)
|
||||||
|
@ -100,7 +101,7 @@ To install use `helm install stable/hackmd`.
|
||||||
For all further details, please check out the offical CodiMD [K8s helm chart](https://github.com/kubernetes/charts/tree/master/stable/hackmd).
|
For all further details, please check out the offical CodiMD [K8s helm chart](https://github.com/kubernetes/charts/tree/master/stable/hackmd).
|
||||||
|
|
||||||
## CodiMD by docker container
|
## CodiMD by docker container
|
||||||
[![Try in PWD](https://cdn.rawgit.com/play-with-docker/stacks/cff22438/assets/images/button.png)](http://play-with-docker.com?stack=https://github.com/hackmdio/docker-hackmd/raw/master/docker-compose.yml&stack_name=codimd)
|
[![Try in PWD](https://cdn.rawgit.com/play-with-docker/stacks/cff22438/assets/images/button.png)](http://play-with-docker.com?stack=https://github.com/hackmdio/codimd-container/raw/master/docker-compose.yml&stack_name=codimd)
|
||||||
|
|
||||||
|
|
||||||
**Debian-based version:**
|
**Debian-based version:**
|
||||||
|
@ -115,11 +116,17 @@ For all further details, please check out the offical CodiMD [K8s helm chart](h
|
||||||
The easiest way to setup CodiMD using docker are using the following three commands:
|
The easiest way to setup CodiMD using docker are using the following three commands:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
git clone https://github.com/hackmdio/docker-hackmd.git
|
git clone https://github.com/hackmdio/codimd-container.git
|
||||||
cd docker-codimd
|
cd codimd-container
|
||||||
docker-compose up
|
docker-compose up
|
||||||
```
|
```
|
||||||
Read more about it in the [docker repository…](https://github.com/hackmdio/docker-hackmd)
|
Read more about it in the [container repository…](https://github.com/hackmdio/codimd-container)
|
||||||
|
|
||||||
|
## Cloudron
|
||||||
|
|
||||||
|
Install CodiMD on [Cloudron](https://cloudron.io):
|
||||||
|
|
||||||
|
[![Install](https://cloudron.io/img/button.svg)](https://cloudron.io/button.html?app=io.hackmd.cloudronapp)
|
||||||
|
|
||||||
# Upgrade
|
# Upgrade
|
||||||
|
|
||||||
|
@ -195,7 +202,7 @@ There are some config settings you need to change in the files below.
|
||||||
| `CMD_GITLAB_CLIENTID` | no example | GitLab API client id |
|
| `CMD_GITLAB_CLIENTID` | no example | GitLab API client id |
|
||||||
| `CMD_GITLAB_CLIENTSECRET` | no example | GitLab API client secret |
|
| `CMD_GITLAB_CLIENTSECRET` | no example | GitLab API client secret |
|
||||||
| `CMD_GITLAB_VERSION` | no example | GitLab API version (v3 or v4) |
|
| `CMD_GITLAB_VERSION` | no example | GitLab API version (v3 or v4) |
|
||||||
| `CMD_MATTERMOST_BASEURL` | no example | Mattermost authentication endpoint |
|
| `CMD_MATTERMOST_BASEURL` | no example | Mattermost authentication endpoint for versions below 5.0. For Mattermost version 5.0 and above, see [guide](docs/guides/auth/mattermost-self-hosted.md). |
|
||||||
| `CMD_MATTERMOST_CLIENTID` | no example | Mattermost API client id |
|
| `CMD_MATTERMOST_CLIENTID` | no example | Mattermost API client id |
|
||||||
| `CMD_MATTERMOST_CLIENTSECRET` | no example | Mattermost API client secret |
|
| `CMD_MATTERMOST_CLIENTSECRET` | no example | Mattermost API client secret |
|
||||||
| `CMD_DROPBOX_CLIENTID` | no example | Dropbox API client id |
|
| `CMD_DROPBOX_CLIENTID` | no example | Dropbox API client id |
|
||||||
|
|
58
docs/guides/auth/mattermost-self-hosted.md
Normal file
58
docs/guides/auth/mattermost-self-hosted.md
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
Authentication guide - Mattermost (self-hosted)
|
||||||
|
===
|
||||||
|
|
||||||
|
*Note: The Mattermost setup portion of this document is just a quick guide. See the [official documentation](https://docs.mattermost.com/developer/oauth-2-0-applications.html) for more details.*
|
||||||
|
|
||||||
|
This guide uses the generic OAuth2 module for compatibility with Mattermost version 5.0 and above.
|
||||||
|
|
||||||
|
1. Sign-in with an administrator account to your Mattermost instance
|
||||||
|
2. Make sure **OAuth 2.0 Service Provider** is enabled in the Main Menu (menu button next to your username in the top left corner) --> System Console --> Custom Integrations menu, which you can find at `https://your.mattermost.domain/admin_console/integrations/custom`
|
||||||
|
|
||||||
|
![mattermost-enable-oauth2](../images/auth/mattermost-enable-oauth2.png)
|
||||||
|
|
||||||
|
3. Navigate to the OAuth integration settings through Main Menu --> Integrations --> OAuth 2.0 Applications, at `https://your.mattermost.domain/yourteam/integrations/oauth2-apps`
|
||||||
|
4. Click on the **Add OAuth 2.0 Application** button to add a new OAuth application
|
||||||
|
|
||||||
|
![mattermost-oauth-app-add](../images/auth/mattermost-oauth-app-add.png)
|
||||||
|
|
||||||
|
5. Fill out the form and click **Save**
|
||||||
|
|
||||||
|
![mattermost-oauth-app-form](../images/auth/mattermost-oauth-app-form.png)
|
||||||
|
|
||||||
|
*Note: The callback URL is \<your-codimd-url\>/auth/oauth2/callback*
|
||||||
|
|
||||||
|
6. After saving the application, you'll receive the Client ID and Client Secret
|
||||||
|
|
||||||
|
![mattermost-oauth-app-done](../images/auth/mattermost-oauth-app-done.png)
|
||||||
|
|
||||||
|
7. Add the Client ID and Client Secret to your config.json file or pass them as environment variables
|
||||||
|
* config.json:
|
||||||
|
````javascript
|
||||||
|
{
|
||||||
|
"production": {
|
||||||
|
"oauth2": {
|
||||||
|
"baseURL": "https://your.mattermost.domain",
|
||||||
|
"userProfileURL": "https://your.mattermost.domain/api/v4/users/me",
|
||||||
|
"userProfileUsernameAttr": "id",
|
||||||
|
"userProfileDisplayNameAttr": "username",
|
||||||
|
"userProfileEmailAttr": "email",
|
||||||
|
"tokenURL": "https://your.mattermost.domain/oauth/access_token",
|
||||||
|
"authorizationURL": "https://your.mattermost.domain/oauth/authorize",
|
||||||
|
"clientID": "ii4p1u3jz7dXXXXXXXXXXXXXXX",
|
||||||
|
"clientSecret": "mqzzx6fydbXXXXXXXXXXXXXXXX"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
````
|
||||||
|
* environment variables:
|
||||||
|
````
|
||||||
|
CMD_OAUTH2_BASEURL=https://your.mattermost.domain
|
||||||
|
CMD_OAUTH2_USER_PROFILE_URL=https://your.mattermost.domain/api/v4/users/me
|
||||||
|
CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR=id
|
||||||
|
CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR=username
|
||||||
|
CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR=email
|
||||||
|
CMD_OAUTH2_TOKEN_URL=https://your.mattermost.domain/oauth/access_token
|
||||||
|
CMD_OAUTH2_AUTHORIZATION_URL=https://your.mattermost.domain/oauth/authorize
|
||||||
|
CMD_OAUTH2_CLIENT_ID=ii4p1u3jz7dXXXXXXXXXXXXXXX
|
||||||
|
CMD_OAUTH2_CLIENT_SECRET=mqzzx6fydbXXXXXXXXXXXXXXXX
|
||||||
|
````
|
BIN
docs/guides/images/auth/mattermost-enable-oauth2.png
Normal file
BIN
docs/guides/images/auth/mattermost-enable-oauth2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
docs/guides/images/auth/mattermost-oauth-app-add.png
Normal file
BIN
docs/guides/images/auth/mattermost-oauth-app-add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
BIN
docs/guides/images/auth/mattermost-oauth-app-done.png
Normal file
BIN
docs/guides/images/auth/mattermost-oauth-app-done.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
BIN
docs/guides/images/auth/mattermost-oauth-app-form.png
Normal file
BIN
docs/guides/images/auth/mattermost-oauth-app-form.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
|
@ -104,8 +104,8 @@ config.isOAuth2Enable = config.oauth2.clientID && config.oauth2.clientSecret
|
||||||
config.isPDFExportEnable = config.allowPDFExport
|
config.isPDFExportEnable = config.allowPDFExport
|
||||||
|
|
||||||
// Check gitlab api version
|
// Check gitlab api version
|
||||||
if (config.gitlab.version !== 'v4' || config.gitlab.version !== 'v3') {
|
if (config.gitlab.version !== 'v4' && config.gitlab.version !== 'v3') {
|
||||||
logger.warn('config.js contains wrong version (' + config.gitlab.version + ') for gitlab api; it should be \'v3\' or \'v4\'. Defaulting to v3')
|
logger.warn('config.js contains wrong version (' + config.gitlab.version + ') for gitlab api; it should be \'v3\' or \'v4\'. Defaulting to v4')
|
||||||
config.gitlab.version = 'v4'
|
config.gitlab.version = 'v4'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,10 @@ exports.generateAvatar = function (name) {
|
||||||
|
|
||||||
exports.generateAvatarURL = function (name, email = '', big = true) {
|
exports.generateAvatarURL = function (name, email = '', big = true) {
|
||||||
let photo
|
let photo
|
||||||
|
if (typeof email !== 'string') {
|
||||||
|
email = '' + name + '@example.com'
|
||||||
|
}
|
||||||
|
|
||||||
if (email !== '' && config.allowGravatar) {
|
if (email !== '' && config.allowGravatar) {
|
||||||
photo = 'https://www.gravatar.com/avatar/' + md5(email.toLowerCase())
|
photo = 'https://www.gravatar.com/avatar/' + md5(email.toLowerCase())
|
||||||
if (big) {
|
if (big) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ module.exports = {
|
||||||
defaultValue: 0
|
defaultValue: 0
|
||||||
})
|
})
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'shortid'") {
|
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'shortid'" || error.message === 'column "shortid" of relation "Notes" already exists') {
|
||||||
console.log('Migration has already run… ignoring.')
|
console.log('Migration has already run… ignoring.')
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
|
|
|
@ -8,7 +8,7 @@ module.exports = {
|
||||||
type: Sequelize.DATE
|
type: Sequelize.DATE
|
||||||
})
|
})
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'lastchangeuserId'") {
|
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'lastchangeuserId'" || error.message === 'column "lastchangeuserId" of relation "Notes" already exists') {
|
||||||
console.log('Migration has already run… ignoring.')
|
console.log('Migration has already run… ignoring.')
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
|
|
|
@ -8,7 +8,7 @@ module.exports = {
|
||||||
indicesType: 'UNIQUE'
|
indicesType: 'UNIQUE'
|
||||||
})
|
})
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'alias'") {
|
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'alias'" || error.message === 'column "alias" of relation "Notes" already exists') {
|
||||||
console.log('Migration has already run… ignoring.')
|
console.log('Migration has already run… ignoring.')
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
|
|
|
@ -4,7 +4,7 @@ module.exports = {
|
||||||
return queryInterface.addColumn('Users', 'accessToken', Sequelize.STRING).then(function () {
|
return queryInterface.addColumn('Users', 'accessToken', Sequelize.STRING).then(function () {
|
||||||
return queryInterface.addColumn('Users', 'refreshToken', Sequelize.STRING)
|
return queryInterface.addColumn('Users', 'refreshToken', Sequelize.STRING)
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'accessToken'") {
|
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'accessToken'" || error.message === 'column "accessToken" of relation "Users" already exists') {
|
||||||
console.log('Migration has already run… ignoring.')
|
console.log('Migration has already run… ignoring.')
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
|
|
|
@ -16,7 +16,7 @@ module.exports = {
|
||||||
updatedAt: Sequelize.DATE
|
updatedAt: Sequelize.DATE
|
||||||
})
|
})
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'savedAt'") {
|
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'savedAt'" || error.message === 'column "savedAt" of relation "Notes" already exists') {
|
||||||
console.log('Migration has already run… ignoring.')
|
console.log('Migration has already run… ignoring.')
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
|
|
|
@ -17,7 +17,7 @@ module.exports = {
|
||||||
updatedAt: Sequelize.DATE
|
updatedAt: Sequelize.DATE
|
||||||
})
|
})
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'authorship'") {
|
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'authorship'" || error.message === 'column "authorship" of relation "Notes" already exists') {
|
||||||
console.log('Migration has already run… ignoring.')
|
console.log('Migration has already run… ignoring.')
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: function (queryInterface, Sequelize) {
|
up: function (queryInterface, Sequelize) {
|
||||||
return queryInterface.addColumn('Notes', 'deletedAt', Sequelize.DATE).catch(function (error) {
|
return queryInterface.addColumn('Notes', 'deletedAt', Sequelize.DATE).catch(function (error) {
|
||||||
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'deletedAt'") {
|
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'deletedAt'" || error.message === 'column "deletedAt" of relation "Notes" already exists') {
|
||||||
console.log('Migration has already run… ignoring.')
|
console.log('Migration has already run… ignoring.')
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
|
|
|
@ -3,14 +3,14 @@ module.exports = {
|
||||||
up: function (queryInterface, Sequelize) {
|
up: function (queryInterface, Sequelize) {
|
||||||
return queryInterface.addColumn('Users', 'email', Sequelize.TEXT).then(function () {
|
return queryInterface.addColumn('Users', 'email', Sequelize.TEXT).then(function () {
|
||||||
return queryInterface.addColumn('Users', 'password', Sequelize.TEXT).catch(function (error) {
|
return queryInterface.addColumn('Users', 'password', Sequelize.TEXT).catch(function (error) {
|
||||||
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'password'") {
|
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'password'" || error.message === 'column "password" of relation "Users" already exists') {
|
||||||
console.log('Migration has already run… ignoring.')
|
console.log('Migration has already run… ignoring.')
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'email'") {
|
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'email'" || error.message === 'column "email" of relation "Users" already exists') {
|
||||||
console.log('Migration has already run… ignoring.')
|
console.log('Migration has already run… ignoring.')
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
"archiver": "^2.1.1",
|
"archiver": "^2.1.1",
|
||||||
"async": "^2.1.4",
|
"async": "^2.1.4",
|
||||||
"aws-sdk": "^2.7.20",
|
"aws-sdk": "^2.7.20",
|
||||||
"base64url": "^3.0.0",
|
|
||||||
"azure-storage": "^2.7.0",
|
"azure-storage": "^2.7.0",
|
||||||
|
"base64url": "^3.0.0",
|
||||||
"blueimp-md5": "^2.6.0",
|
"blueimp-md5": "^2.6.0",
|
||||||
"body-parser": "^1.15.2",
|
"body-parser": "^1.15.2",
|
||||||
"bootstrap": "^3.3.7",
|
"bootstrap": "^3.3.7",
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
"keymaster": "^1.6.2",
|
"keymaster": "^1.6.2",
|
||||||
"list.js": "^1.5.0",
|
"list.js": "^1.5.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"lz-string": "1.4.4",
|
"lz-string": "git+https://github.com/hackmdio/lz-string.git",
|
||||||
"markdown-it": "^8.2.2",
|
"markdown-it": "^8.2.2",
|
||||||
"markdown-it-abbr": "^1.0.4",
|
"markdown-it-abbr": "^1.0.4",
|
||||||
"markdown-it-container": "^2.0.0",
|
"markdown-it-container": "^2.0.0",
|
||||||
|
@ -78,8 +78,8 @@
|
||||||
"markdown-it-sup": "^1.0.0",
|
"markdown-it-sup": "^1.0.0",
|
||||||
"markdown-pdf": "^9.0.0",
|
"markdown-pdf": "^9.0.0",
|
||||||
"mathjax": "~2.7.0",
|
"mathjax": "~2.7.0",
|
||||||
"mermaid": "~7.1.0",
|
|
||||||
"mattermost": "^3.4.0",
|
"mattermost": "^3.4.0",
|
||||||
|
"mermaid": "~7.1.0",
|
||||||
"meta-marked": "^0.4.2",
|
"meta-marked": "^0.4.2",
|
||||||
"method-override": "^2.3.7",
|
"method-override": "^2.3.7",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
|
@ -98,8 +98,8 @@
|
||||||
"passport-ldapauth": "^2.0.0",
|
"passport-ldapauth": "^2.0.0",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"passport-oauth2": "^1.4.0",
|
"passport-oauth2": "^1.4.0",
|
||||||
"passport-twitter": "^1.0.4",
|
|
||||||
"passport-saml": "^0.31.0",
|
"passport-saml": "^0.31.0",
|
||||||
|
"passport-twitter": "^1.0.4",
|
||||||
"passport.socketio": "^3.7.0",
|
"passport.socketio": "^3.7.0",
|
||||||
"pdfobject": "^2.0.201604172",
|
"pdfobject": "^2.0.201604172",
|
||||||
"pg": "^6.1.2",
|
"pg": "^6.1.2",
|
||||||
|
|
|
@ -4612,9 +4612,9 @@ lru-queue@0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
es5-ext "~0.10.2"
|
es5-ext "~0.10.2"
|
||||||
|
|
||||||
lz-string@1.4.4:
|
"lz-string@git+https://github.com/hackmdio/lz-string.git":
|
||||||
version "1.4.4"
|
version "1.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
|
resolved "git+https://github.com/hackmdio/lz-string.git#6edfccb79cd8c210f03fd3bf18e41ca144fbeefb"
|
||||||
|
|
||||||
macaddress@^0.2.8:
|
macaddress@^0.2.8:
|
||||||
version "0.2.8"
|
version "0.2.8"
|
||||||
|
|
Loading…
Reference in a new issue