Merge remote-tracking branch 'upstream/master' into DepauMD

This commit is contained in:
Davide Depau 2019-04-11 22:30:56 +02:00
commit 107f92e6fd
98 changed files with 1648 additions and 1282 deletions

View file

@ -17,3 +17,9 @@ trim_trailing_whitespace = false
[{.travis.yml,npm-shrinkwrap.json,package.json}] [{.travis.yml,npm-shrinkwrap.json,package.json}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
[locales/*.json]
# this is the exact style poeditor.com exports, so this should prevent churn.
insert_final_newline = false
indent_style = space
indent_size = 4

1
.gitignore vendored
View file

@ -8,7 +8,6 @@ composer.lock
.idea/ .idea/
Thumbs.db Thumbs.db
npm-debug.log npm-debug.log
hackmd_io
newrelic_agent.log newrelic_agent.log
logs/ logs/
tmp/ tmp/

View file

@ -30,13 +30,6 @@ jobs:
script: script:
- shellcheck bin/heroku bin/setup - shellcheck bin/heroku bin/setup
language: generic language: generic
- env: task=doctoc
install: npm install doctoc
script:
- cp README.md README.md.orig
- npm run doctoc
- diff -q README.md README.md.orig
language: generic
- env: task=json-lint - env: task=json-lint
addons: addons:
apt: apt:

7
CHANGELOG.md Normal file
View file

@ -0,0 +1,7 @@
# CHANGELOG
Please refer to the release notes published under
[`public/docs/release-notes.md`](public/docs/release-notes.md).
These are also available on each CodiMD instance under
https://[domain-name]/release-notes

37
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,37 @@
Contributor Code of Conduct
===
As contributors and maintainers of this project, and in the interest of fostering an open and
welcoming community, we pledge to respect all people who contribute through reporting issues,
posting feature requests, updating documentation, submitting pull requests or patches, and other
activities.
We are committed to making participation in this project a harassment-free experience for everyone,
regardless of level of experience, gender, gender identity and expression, sexual orientation,
disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses, without explicit
permission
* Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits,
code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By
adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently
applying these principles to every aspect of managing this project. Project maintainers who do not
follow or enforce the Code of Conduct may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces when an individual is
representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an
issue or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org),
version 1.2.0, available at
[http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)

View file

@ -3,7 +3,8 @@
When contributing to this repository, please first discuss the change you wish to make via issue, When contributing to this repository, please first discuss the change you wish to make via issue,
email, or any other method with the owners of this repository before making a change. email, or any other method with the owners of this repository before making a change.
Please note we have a code of conduct, please follow it in all your interactions with the project. Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your
interactions with the project.
## Pull Request Process ## Pull Request Process
1. Ensure you signed all your commits with Developer Certificate of Origin (DCO). 1. Ensure you signed all your commits with Developer Certificate of Origin (DCO).
@ -16,44 +17,7 @@ Please note we have a code of conduct, please follow it in all your interactions
5. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 5. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
do not have permission to do that, you may request the second reviewer to merge it for you. do not have permission to do that, you may request the second reviewer to merge it for you.
## Contributor Code of Conduct ## Sign your work
As contributors and maintainers of this project, and in the interest of fostering an open and
welcoming community, we pledge to respect all people who contribute through reporting issues,
posting feature requests, updating documentation, submitting pull requests or patches, and other
activities.
We are committed to making participation in this project a harassment-free experience for everyone,
regardless of level of experience, gender, gender identity and expression, sexual orientation,
disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses, without explicit
permission
* Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits,
code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By
adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently
applying these principles to every aspect of managing this project. Project maintainers who do not
follow or enforce the Code of Conduct may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces when an individual is
representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an
issue or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org),
version 1.2.0, available at
[http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
### Sign your work
We use the Developer Certificate of Origin (DCO) as a additional safeguard We use the Developer Certificate of Origin (DCO) as a additional safeguard
for the CodiMD project. This is a well established and widely used for the CodiMD project. This is a well established and widely used

13
LICENSE
View file

@ -629,8 +629,15 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.> CodiMD - Realtime collaborative markdown notes on all platforms.
Copyright (C) <year> <name of author> Copyright (C) 2019 Christoph (Sheogorath) Kern
Copyright (C) 2019 Claudius Coenen
Copyright (C) 2019 Max Wu
Copyright (C) 2017 Yukai Huang
And more can be found on https://github.com/codimd/server/graphs/contributors
Or in the local AUTHORS file
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU Affero General Public License as published by
@ -658,4 +665,4 @@ specific requirements.
You should also get your employer (if you work as a programmer) or school, You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary. if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>. <http://www.gnu.org/licenses/>.

399
README.md
View file

@ -1,52 +1,70 @@
CodiMD CodiMD
=== ===
[![CodiMD on Gitter][gitter-image]][gitter-url] [![#CodiMD on matrix.org][matrix.org-image]][matrix.org-url]
[![build status][travis-image]][travis-url] [![build status][travis-image]][travis-url]
[![version][github-version-badge]][github-release-page] [![version][github-version-badge]][github-release-page]
[![POEditor][poeditor-image]][poeditor-url] [![POEditor][poeditor-image]][poeditor-url]
CodiMD lets you create real-time collaborative markdown notes on all platforms. CodiMD lets you create real-time collaborative markdown notes. You can test-drive
Inspired by Hackpad, with more focus on speed and flexibility, and build from [HackMD](https://hackmd.io) source code. it by visiting our [CodiMD demo server][codimd-demo].
Feel free to contribute.
Thanks for using! :smile: It is inspired by Hackpad, Etherpad and similar collaborative editors. This
project originated with the team at [HackMD](https://hackmd.io) and now forked
into its own organisation. [A longer writeup can be read in the history doc](docs/history.md).
<!-- START doctoc generated TOC please keep comment here to allow auto update --> [![CodiMD 1.3.2 with its feature demonstration page open](docs/images/CodiMD-1.3.2-features.png)][codimd-demo-features]
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
# Table of Contents
- [HackMD CE became CodiMD](#hackmd-ce-became-codimd)
- [Browsers Requirement](#browsers-requirement)
- [Installation](#installation)
- [Getting started (Native install)](#getting-started-native-install)
- [Prerequisite](#prerequisite)
- [Instructions](#instructions)
- [Heroku Deployment](#heroku-deployment)
- [Kubernetes](#kubernetes)
- [Upgrade](#upgrade)
- [Native setup](#native-setup)
- [Configuration](#configuration)
- [Environment variables (will overwrite other server configs)](#environment-variables-will-overwrite-other-server-configs)
- [Application settings `config.json`](#application-settings-configjson)
- [Third-party integration API key settings](#third-party-integration-api-key-settings)
- [Third-party integration OAuth callback URLs](#third-party-integration-oauth-callback-urls)
- [Developer Notes](#developer-notes)
- [Structure](#structure)
- [Operational Transformation](#operational-transformation)
- [License](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update --> ## Community and Contributions
# HackMD CE became CodiMD We welcome contributions! There's a lot to do: If you would like to report bugs,
the [issue tracker][github-issue-tracker] is the right place. If you can help
translating, find us on [POEditor][poeditor-url]. To get started developing,
take a look at the [docs/dev](docs/dev) directory. In any case: come talk to us,
we'll be delighted to help you with the first steps.
CodiMD was recently renamed from its former name was HackMD. CodiMD is the free software version of HackMD. HackMD EE, which is a SaaS (Software as a Service) product available at [hackmd.io](https://hackmd.io). To stay up to date with our work or get support it's recommended to join our
[Matrix channel][matrix.org-url], stop by our [community forums][codimd-community]
or subscribe to the [release feed][github-release-feed]. We also engage in
regular [community calls][codimd-community-calls] ([RSS](https://community.codimd.org/t/codimd-community-call/19.rss)) which you are very welcome to join.
We decided to change the name to break the confusion between HackMD and CodiMD, formally known as HackMD CE, as it never was an open core project.
*For the whole renaming story, see the [related issue](https://github.com/hackmdio/hackmd/issues/720)* ## Installation / Upgrading
# Browsers Requirement You can run CodiMD in a number of ways, and we created setup instructions for
all of these:
* [Docker](docs/setup/docker.md)
* [Kubernetes](docs/setup/kubernetes.md)
* [Cloudron](docs/setup/cloudron.md)
* [Heroku](docs/setup/heroku.md)
* [manual setup](docs/setup/manual-setup.md)
If you do not wish to run your own setup, you can find a commercial offering at
https://hackmd.io. This is not the same codebase as this one, but it is a very
similar project.
## Configuration
Theres two main ways to configure your CodiMD instance:
[Config file](docs/configuration-config-file.md) or
[environment variables](docs/configuration-env-vars.md). You can choose what
works best for you.
CodiMD can integrate with
* facebook, twitter, github, gitlab, mattermost, dropbox, google, ldap, saml and [oauth2](docs/guides/auth/oauth.md) **for login**
* imgur, s3, minio, azure **for image/attachment storage** (files can also be local!)
* dropbox **for export and import**
More info about that can be found in the configuration docs above.
## Browser support
To use CodiMD, your browser should match or exceed these versions:
- ![Chrome](http://browserbadge.com/chrome/47/18px) Chrome >= 47, Chrome for Android >= 47 - ![Chrome](http://browserbadge.com/chrome/47/18px) Chrome >= 47, Chrome for Android >= 47
- ![Safari](http://browserbadge.com/safari/9/18px) Safari >= 9, iOS Safari >= 8.4 - ![Safari](http://browserbadge.com/safari/9/18px) Safari >= 9, iOS Safari >= 8.4
@ -55,309 +73,28 @@ We decided to change the name to break the confusion between HackMD and CodiMD,
- ![Opera](http://browserbadge.com/opera/34/18px) Opera >= 34, Opera Mini not supported - ![Opera](http://browserbadge.com/opera/34/18px) Opera >= 34, Opera Mini not supported
- Android Browser >= 4.4 - Android Browser >= 4.4
# Installation
## Getting started (Native install) ## Related Tools
### Prerequisite
- Node.js 6.x or up (test up to 7.5.0) and <10.x
- 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))
- `libssl-dev` for building scrypt (see [here](https://github.com/ml1nk/node-scrypt/blob/master/README.md#installation-instructions) for further information)
- For **building** CodiMD we recommend to use a machine with at least **2GB** RAM
### Instructions
1. Download a release and unzip or clone into a directory
2. Enter the directory and type `bin/setup`, which will install npm dependencies and create configs. The setup script is written in Bash, you would need bash as a prerequisite.
3. Setup the configs, see more below
4. Setup environment variables which will overwrite the configs
5. Build front-end bundle by `npm run build` (use `npm run dev` if you are in development)
6. Modify the file named `.sequelizerc`, change the value of the variable `url` with your db connection string
For example: `postgres://username:password@localhost:5432/codimd`
7. Run `node_modules/.bin/sequelize db:migrate`, this step will migrate your db to the latest schema
8. Run the server as you like (node, forever, pm2)
To stay up to date with your installation it's recommended to subscribe the [release feed][github-release-feed].
## Heroku Deployment
You can quickly setup a sample Heroku CodiMD application by clicking the button below.
[![Deploy on Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/hackmdio/codimd/tree/master)
If you deploy it without the button, keep in mind to use the right buildpacks. For details check `app.json`.
## Kubernetes
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).
**Debian-based version:**
[![latest](https://images.microbadger.com/badges/version/hackmdio/hackmd:latest.svg)](https://microbadger.com/images/hackmdio/hackmd "Get your own version badge on microbadger.com") [![](https://images.microbadger.com/badges/image/hackmdio/hackmd:latest.svg)](https://microbadger.com/images/hackmdio/hackmd "Get your own image badge on microbadger.com")
The easiest way to setup CodiMD using docker are using the following three commands:
```console
git clone https://github.com/hackmdio/docker-hackmd.git
cd docker-hackmd
docker-compose up
```
Read more about it in the [container repository…](https://github.com/hackmdio/docker-hackmd)
# Upgrade
## Native setup
If you are upgrading CodiMD from an older version, follow these steps:
1. Fully stop your old server first (important)
2. `git pull` or do whatever that updates the files
3. `npm install` to update dependencies
4. Build front-end bundle by `npm run build` (use `npm run dev` if you are in development)
5. Modify the file named `.sequelizerc`, change the value of the variable `url` with your db connection string
For example: `postgres://username:password@localhost:5432/codimd`
6. Run `node_modules/.bin/sequelize db:migrate`, this step will migrate your db to the latest schema
7. Start your whole new server!
To stay up to date with your installation it's recommended to subscribe the [release feed][github-release-feed].
* **migrate-to-1.1.0**
We deprecated the older lower case config style and moved on to camel case style. Please have a look at the current `config.json.example` and check the warnings on startup.
*Notice: This is not a breaking change right now but in the future*
* [**migration-to-0.5.0**](https://github.com/hackmdio/migration-to-0.5.0)
We don't use LZString to compress socket.io data and DB data after version 0.5.0.
Please run the migration tool if you're upgrading from the old version.
* [**migration-to-0.4.0**](https://github.com/hackmdio/migration-to-0.4.0)
We've dropped MongoDB after version 0.4.0.
So here is the migration tool for you to transfer the old DB data to the new DB.
This tool is also used for official service.
# Configuration
There are some config settings you need to change in the files below.
```
./config.json ----application settings
```
## Environment variables (will overwrite other server configs)
| variables | example values | description |
| --------- | ------ | ----------- |
| `NODE_ENV` | `production` or `development` | set current environment (will apply corresponding settings in the `config.json`) |
| `DEBUG` | `true` or `false` | set debug mode; show more logs |
| `CMD_CONFIG_FILE` | `/path/to/config.json` | optional override for the path to CodiMD's config file |
| `CMD_DOMAIN` | `codimd.org` | domain name |
| `CMD_URL_PATH` | `codimd` | sub URL path, like `www.example.com/<URL_PATH>` |
| `CMD_HOST` | `localhost` | host to listen on |
| `CMD_PORT` | `80` | web app port |
| `CMD_PATH` | `/var/run/codimd.sock` | path to UNIX domain socket to listen on (if specified, `CMD_HOST` and `CMD_PORT` are ignored) |
| `CMD_LOGLEVEL` | `info` | Defines what kind of logs are provided to stdout. |
| `CMD_ALLOW_ORIGIN` | `localhost, codimd.org` | domain name whitelist (use comma to separate) |
| `CMD_PROTOCOL_USESSL` | `true` or `false` | set to use SSL protocol for resources path (only applied when domain is set) |
| `CMD_URL_ADDPORT` | `true` or `false` | set to add port on callback URL (ports `80` or `443` won't be applied) (only applied when domain is set) |
| `CMD_USECDN` | `true` or `false` | set to use CDN resources or not (default is `true`) |
| `CMD_ALLOW_ANONYMOUS` | `true` or `false` | set to allow anonymous usage (default is `true`) |
| `CMD_ALLOW_ANONYMOUS_EDITS` | `true` or `false` | if `allowAnonymous` is `true`, allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`) |
| `CMD_ALLOW_FREEURL` | `true` or `false` | set to allow new note creation by accessing a nonexistent note URL |
| `CMD_FORBIDDEN_NODE_IDS` | `'robots.txt'` | disallow creation of notes, even if `CMD_ALLOW_FREEURL` is `true` |
| `CMD_DEFAULT_PERMISSION` | `freely`, `editable`, `limited`, `locked` or `private` | set notes default permission (only applied on signed users) |
| `CMD_DB_URL` | `mysql://localhost:3306/database` | set the database URL |
| `CMD_SESSION_SECRET` | no example | Secret used to sign the session cookie. If non is set, one will randomly generated on startup |
| `CMD_SESSION_LIFE` | `1209600000` | Session life time. (milliseconds) |
| `CMD_FACEBOOK_CLIENTID` | no example | Facebook API client id |
| `CMD_FACEBOOK_CLIENTSECRET` | no example | Facebook API client secret |
| `CMD_TWITTER_CONSUMERKEY` | no example | Twitter API consumer key |
| `CMD_TWITTER_CONSUMERSECRET` | no example | Twitter API consumer secret |
| `CMD_GITHUB_CLIENTID` | no example | GitHub API client id |
| `CMD_GITHUB_CLIENTSECRET` | no example | GitHub API client secret |
| `CMD_GITLAB_SCOPE` | `read_user` or `api` | GitLab API requested scope (default is `api`) (GitLab snippet import/export need `api` scope) |
| `CMD_GITLAB_BASEURL` | no example | GitLab authentication endpoint, set to use other endpoint than GitLab.com (optional) |
| `CMD_GITLAB_CLIENTID` | no example | GitLab API client id |
| `CMD_GITLAB_CLIENTSECRET` | no example | GitLab API client secret |
| `CMD_GITLAB_VERSION` | no example | GitLab API version (v3 or v4) |
| `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_CLIENTSECRET` | no example | Mattermost API client secret |
| `CMD_DROPBOX_CLIENTID` | no example | Dropbox API client id |
| `CMD_DROPBOX_CLIENTSECRET` | no example | Dropbox API client secret |
| `CMD_GOOGLE_CLIENTID` | no example | Google API client id |
| `CMD_GOOGLE_CLIENTSECRET` | no example | Google API client secret |
| `CMD_LDAP_URL` | `ldap://example.com` | URL of LDAP server |
| `CMD_LDAP_BINDDN` | no example | bindDn for LDAP access |
| `CMD_LDAP_BINDCREDENTIALS` | no example | bindCredentials for LDAP access |
| `CMD_LDAP_SEARCHBASE` | `o=users,dc=example,dc=com` | LDAP directory to begin search from |
| `CMD_LDAP_SEARCHFILTER` | `(uid={{username}})` | LDAP filter to search with |
| `CMD_LDAP_SEARCHATTRIBUTES` | `displayName, mail` | LDAP attributes to search with (use comma to separate) |
| `CMD_LDAP_USERIDFIELD` | `uidNumber` or `uid` or `sAMAccountName` | The LDAP field which is used uniquely identify a user on CodiMD |
| `CMD_LDAP_USERNAMEFIELD` | Fallback to userid | The LDAP field which is used as the username on CodiMD |
| `CMD_LDAP_TLS_CA` | `server-cert.pem, root.pem` | Root CA for LDAP TLS in PEM format (use comma to separate) |
| `CMD_LDAP_PROVIDERNAME` | `My institution` | Optional name to be displayed at login form indicating the LDAP provider |
| `CMD_SAML_IDPSSOURL` | `https://idp.example.com/sso` | authentication endpoint of IdP. for details, see [guide](docs/guides/auth/saml-onelogin.md). |
| `CMD_SAML_IDPCERT` | `/path/to/cert.pem` | certificate file path of IdP in PEM format |
| `CMD_SAML_ISSUER` | no example | identity of the service provider (optional, default: serverurl)" |
| `CMD_SAML_IDENTIFIERFORMAT` | no example | name identifier format (optional, default: `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`) |
| `CMD_SAML_GROUPATTRIBUTE` | `memberOf` | attribute name for group list (optional) |
| `CMD_SAML_REQUIREDGROUPS` | `Hackmd-users` | group names that allowed (use vertical bar to separate) (optional) |
| `CMD_SAML_EXTERNALGROUPS` | `Temporary-staff` | group names that not allowed (use vertical bar to separate) (optional) |
| `CMD_SAML_ATTRIBUTE_ID` | `sAMAccountName` | attribute map for `id` (optional, default: NameID of SAML response) |
| `CMD_SAML_ATTRIBUTE_USERNAME` | `mailNickname` | attribute map for `username` (optional, default: NameID of SAML response) |
| `CMD_SAML_ATTRIBUTE_EMAIL` | `mail` | attribute map for `email` (optional, default: NameID of SAML response if `CMD_SAML_IDENTIFIERFORMAT` is default) |
| `CMD_OAUTH2_USER_PROFILE_URL` | `https://example.com` | where retrieve information about a user after succesful login. Needs to output JSON. (no default value) Refer to the [Mattermost](docs/guides/auth/mattermost-self-hosted.md) or [Nextcloud](docs/guides/auth/nextcloud.md) examples for more details on all of the `CMD_OAUTH2...` options. |
| `CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR` | `name` | where to find the username in the JSON from the user profile URL. (no default value)|
| `CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR` | `display-name` | where to find the display-name in the JSON from the user profile URL. (no default value) |
| `CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR` | `email` | where to find the email address in the JSON from the user profile URL. (no default value) |
| `CMD_OAUTH2_TOKEN_URL` | `https://example.com` | sometimes called token endpoint, please refer to the documentation of your OAuth2 provider (no default value) |
| `CMD_OAUTH2_AUTHORIZATION_URL` | `https://example.com` | authorization URL of your provider, please refer to the documentation of your OAuth2 provider (no default value) |
| `CMD_OAUTH2_CLIENT_ID` | `afae02fckafd...` | you will get this from your OAuth2 provider when you register CodiMD as OAuth2-client, (no default value) |
| `CMD_OAUTH2_CLIENT_SECRET` | `afae02fckafd...` | you will get this from your OAuth2 provider when you register CodiMD as OAuth2-client, (no default value) |
| `CMD_OAUTH2_PROVIDERNAME` | `My institution` | Optional name to be displayed at login form indicating the oAuth2 provider |
| `CMD_IMGUR_CLIENTID` | no example | Imgur API client id |
| `CMD_EMAIL` | `true` or `false` | set to allow email signin |
| `CMD_ALLOW_PDF_EXPORT` | `true` or `false` | Enable or disable PDF exports |
| `CMD_ALLOW_EMAIL_REGISTER` | `true` or `false` | set to allow email register (only applied when email is set, default is `true`. Note `bin/manage_users` might help you if registration is `false`.) |
| `CMD_ALLOW_GRAVATAR` | `true` or `false` | set to `false` to disable gravatar as profile picture source on your instance |
| `CMD_IMAGE_UPLOAD_TYPE` | `imgur`, `s3`, `minio` or `filesystem` | Where to upload images. For S3, see our Image Upload Guides for [S3](docs/guides/s3-image-upload.md) or [Minio](docs/guides/minio-image-upload.md) |
| `CMD_S3_ACCESS_KEY_ID` | no example | AWS access key id |
| `CMD_S3_SECRET_ACCESS_KEY` | no example | AWS secret key |
| `CMD_S3_REGION` | `ap-northeast-1` | AWS S3 region |
| `CMD_S3_BUCKET` | no example | AWS S3 bucket name |
| `CMD_MINIO_ACCESS_KEY` | no example | Minio access key |
| `CMD_MINIO_SECRET_KEY` | no example | Minio secret key |
| `CMD_MINIO_ENDPOINT` | `minio.example.org` | Address of your Minio endpoint/instance |
| `CMD_MINIO_PORT` | `9000` | Port that is used for your Minio instance |
| `CMD_MINIO_SECURE` | `true` | If set to `true` HTTPS is used for Minio |
| `CMD_AZURE_CONNECTION_STRING` | no example | Azure Blob Storage connection string |
| `CMD_AZURE_CONTAINER` | no example | Azure Blob Storage container name (automatically created if non existent) |
| `CMD_HSTS_ENABLE` | ` true` | set to enable [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) if HTTPS is also enabled (default is ` true`) |
| `CMD_HSTS_INCLUDE_SUBDOMAINS` | `true` | set to include subdomains in HSTS (default is `true`) |
| `CMD_HSTS_MAX_AGE` | `31536000` | max duration in seconds to tell clients to keep HSTS status (default is a year) |
| `CMD_HSTS_PRELOAD` | `true` | whether to allow preloading of the site's HSTS status (e.g. into browsers) |
| `CMD_CSP_ENABLE` | `true` | whether to enable Content Security Policy (directives cannot be configured with environment variables) |
| `CMD_CSP_REPORTURI` | `https://<someid>.report-uri.com/r/d/csp/enforce` | Allows to add a URL for CSP reports in case of violations |
| `CMD_SOURCE_URL` | `https://github.com/hackmdio/codimd/tree/<current commit>` | Provides the link to the source code of CodiMD on the entry page (Please, make sure you change this when you run a modified version) |
***Note:** Due to the rename process we renamed all `HMD_`-prefix variables to be `CMD_`-prefixed. The old ones continue to work.*
## Application settings `config.json`
| variables | example values | description |
| --------- | ------ | ----------- |
| `debug` | `true` or `false` | set debug mode, show more logs |
| `domain` | `localhost` | domain name |
| `urlPath` | `codimd` | sub URL path, like `www.example.com/<urlpath>` |
| `host` | `localhost` | host to listen on |
| `port` | `80` | web app port |
| `path` | `/var/run/codimd.sock` | path to UNIX domain socket to listen on (if specified, `host` and `port` are ignored) |
| `loglevel` | `info` | Defines what kind of logs are provided to stdout. |
| `allowOrigin` | `['localhost']` | domain name whitelist |
| `useSSL` | `true` or `false` | set to use SSL server (if `true`, will auto turn on `protocolUseSSL`) |
| `hsts` | `{"enable": true, "maxAgeSeconds": 31536000, "includeSubdomains": true, "preload": true}` | [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) options to use with HTTPS (default is the example value, max age is a year) |
| `csp` | `{"enable": true, "directives": {"scriptSrc": "trustworthy-scripts.example.com"}, "upgradeInsecureRequests": "auto", "addDefaults": true}` | Configures [Content Security Policy](https://helmetjs.github.io/docs/csp/). Directives are passed to Helmet - see [their documentation](https://helmetjs.github.io/docs/csp/) for more information on the format. Some defaults are added to the configured values so that the application doesn't break. To disable this behaviour, set `addDefaults` to `false`. Further, if `usecdn` is on, some CDN locations are allowed too. By default (`auto`), insecure (HTTP) requests are upgraded to HTTPS via CSP if `useSSL` is on. To change this behaviour, set `upgradeInsecureRequests` to either `true` or `false`. |
| `protocolUseSSL` | `true` or `false` | set to use SSL protocol for resources path (only applied when domain is set) |
| `urlAddPort` | `true` or `false` | set to add port on callback URL (ports `80` or `443` won't be applied) (only applied when domain is set) |
| `useCDN` | `true` or `false` | set to use CDN resources or not (default is `true`) |
| `allowAnonymous` | `true` or `false` | set to allow anonymous usage (default is `true`) |
| `allowAnonymousEdits` | `true` or `false` | if `allowAnonymous` is `true`: allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`) |
| `allowFreeURL` | `true` or `false` | set to allow new note creation by accessing a nonexistent note URL |
| `forbiddenNoteIDs` | `['robots.txt']` | disallow creation of notes, even if `allowFreeUrl` is `true` |
| `defaultPermission` | `freely`, `editable`, `limited`, `locked`, `protected` or `private` | set notes default permission (only applied on signed users) |
| `dbURL` | `mysql://localhost:3306/database` | set the db URL; if set, then db config (below) won't be applied |
| `db` | `{ "dialect": "sqlite", "storage": "./db.codimd.sqlite" }` | set the db configs, [see more here](http://sequelize.readthedocs.org/en/latest/api/sequelize/) |
| `sslKeyPath` | `./cert/client.key` | SSL key path<sup>1</sup> (only need when you set `useSSL`) |
| `sslCertPath` | `./cert/codimd_io.crt` | SSL cert path<sup>1</sup> (only need when you set `useSSL`) |
| `sslCAPath` | `['./cert/COMODORSAAddTrustCA.crt']` | SSL ca chain<sup>1</sup> (only need when you set `useSSL`) |
| `dhParamPath` | `./cert/dhparam.pem` | SSL dhparam path<sup>1</sup> (only need when you set `useSSL`) |
| `tmpPath` | `./tmp/` | temp directory path<sup>1</sup> |
| `defaultNotePath` | `./public/default.md` | default note file path<sup>1</sup> |
| `docsPath` | `./public/docs` | docs directory path<sup>1</sup> |
| `viewPath` | `./public/views` | template directory path<sup>1</sup> |
| `uploadsPath` | `./public/uploads` | uploads directory<sup>1</sup> - needs to be persistent when you use imageUploadType `filesystem` |
| `sessionName` | `connect.sid` | cookie session name |
| `sessionSecret` | `secret` | cookie session secret |
| `sessionLife` | `14 * 24 * 60 * 60 * 1000` | cookie session life |
| `staticCacheTime` | `1 * 24 * 60 * 60 * 1000` | static file cache time |
| `heartbeatInterval` | `5000` | socket.io heartbeat interval |
| `heartbeatTimeout` | `10000` | socket.io heartbeat timeout |
| `documentMaxLength` | `100000` | note max length |
| `email` | `true` or `false` | set to allow email signin |
| `oauth2` | `{baseURL: ..., userProfileURL: ..., userProfileUsernameAttr: ..., userProfileDisplayNameAttr: ..., userProfileEmailAttr: ..., tokenURL: ..., authorizationURL: ..., clientID: ..., clientSecret: ...}` | An object detailing your OAuth2 provider. Refer to the [Mattermost](docs/guides/auth/mattermost-self-hosted.md) or [Nextcloud](docs/guides/auth/nextcloud.md) examples for more details!|
| `allowEmailRegister` | `true` or `false` | set to allow email register (only applied when email is set, default is `true`. Note `bin/manage_users` might help you if registration is `false`.) |
| `allowGravatar` | `true` or `false` | set to `false` to disable gravatar as profile picture source on your instance |
| `imageUploadType` | `imgur`, `s3`, `minio`, `azure` or `filesystem`(default) | Where to upload images. For S3, see our Image Upload Guides for [S3](docs/guides/s3-image-upload.md) or [Minio](docs/guides/minio-image-upload.md)|
| `minio` | `{ "accessKey": "YOUR_MINIO_ACCESS_KEY", "secretKey": "YOUR_MINIO_SECRET_KEY", "endpoint": "YOUR_MINIO_HOST", port: 9000, secure: true }` | When `imageUploadType` is set to `minio`, you need to set this key. Also checkout our [Minio Image Upload Guide](docs/guides/minio-image-upload.md) |
| `s3` | `{ "accessKeyId": "YOUR_S3_ACCESS_KEY_ID", "secretAccessKey": "YOUR_S3_ACCESS_KEY", "region": "YOUR_S3_REGION" }` | When `imageuploadtype` be set to `s3`, you would also need to setup this key, check our [S3 Image Upload Guide](docs/guides/s3-image-upload.md) |
| `s3bucket` | `YOUR_S3_BUCKET_NAME` | bucket name when `imageUploadType` is set to `s3` or `minio` |
| `sourceURL` | `https://github.com/hackmdio/codimd/tree/<current commit>` | Provides the link to the source code of CodiMD on the entry page (Please, make sure you change this when you run a modified version) |
<sup>1</sup>: relative paths are based on CodiMD's base directory
## Third-party integration API key settings
| service | settings location | description |
| ------- | --------- | ----------- |
| facebook, twitter, github, gitlab, mattermost, dropbox, google, ldap, saml | environment variables or `config.json` | for signin |
| imgur, s3, minio, azure | environment variables or `config.json` | for image upload |
| dropbox(`dropbox/appKey`) | `config.json` | for export and import |
## Third-party integration OAuth callback URLs
| service | callback URL (after the server URL) |
| ------- | --------- |
| facebook | `/auth/facebook/callback` |
| twitter | `/auth/twitter/callback` |
| github | `/auth/github/callback` |
| gitlab | `/auth/gitlab/callback` |
| mattermost | `/auth/mattermost/callback` |
| dropbox | `/auth/dropbox/callback` |
| google | `/auth/google/callback` |
| saml | `/auth/saml/callback` |
# Developer Notes
## Structure
```text
codimd/
├── tmp/ --- temporary files
├── docs/ --- document files
├── lib/ --- server libraries
└── public/ --- client files
├── css/ --- css styles
├── js/ --- js scripts
├── vendor/ --- vendor includes
└── views/ --- view templates
```
## Operational Transformation
From 0.3.2, we started supporting operational transformation.
It makes concurrent editing safe and will not break up other users' operations.
Additionally, now can show other clients' selections.
See more at [http://operational-transformation.github.io/](http://operational-transformation.github.io/)
Our community has created related tools, we'd like to highlight [codimd-cli](https://github.com/codimd/cli)
which lets you use CodiMD from the comfort of your command line.
# License # License
**License under AGPL.** Licensed under AGPLv3. For our list of contributors, see [AUTHORS](AUTHORS).
[gitter-image]: https://img.shields.io/badge/gitter-hackmdio/codimd-blue.svg [matrix.org-image]: https://img.shields.io/badge/Matrix.org-%23CodiMD@matrix.org-green.svg
[gitter-url]: https://gitter.im/hackmdio/hackmd [matrix.org-url]: https://riot.im/app/#/room/#codimd:matrix.org
[travis-image]: https://travis-ci.org/hackmdio/codimd.svg?branch=master [travis-image]: https://travis-ci.org/codimd/server.svg?branch=master
[travis-url]: https://travis-ci.org/hackmdio/codimd [travis-url]: https://travis-ci.org/codimd/server
[github-version-badge]: https://img.shields.io/github/release/hackmdio/codimd.svg [github-version-badge]: https://img.shields.io/github/release/codimd/server.svg
[github-release-page]: https://github.com/hackmdio/codimd/releases [github-release-page]: https://github.com/codimd/server/releases
[github-release-feed]: https://github.com/hackmdio/codimd/releases.atom [github-release-feed]: https://github.com/codimd/server/releases.atom
[github-issue-tracker]: https://github.com/codimd/server/issues/
[poeditor-image]: https://img.shields.io/badge/POEditor-translate-blue.svg [poeditor-image]: https://img.shields.io/badge/POEditor-translate-blue.svg
[poeditor-url]: https://poeditor.com/join/project/q0nuPWyztp [poeditor-url]: https://poeditor.com/join/project/1OpGjF2Jir
[codimd-demo]: https://demo.codimd.org
[codimd-demo-features]: https://demo.codimd.org/features
[codimd-community]: https://community.codimd.org
[codimd-community-calls]: https://community.codimd.org/t/codimd-community-call/19

1
app.js
View file

@ -115,6 +115,7 @@ if (config.csp.enable) {
i18n.configure({ i18n.configure({
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'], 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'],
cookie: 'locale', cookie: 'locale',
indent: ' ', // this is the style poeditor.com exports it, this creates less churn
directory: path.join(__dirname, '/locales'), directory: path.join(__dirname, '/locales'),
updateFiles: config.updateI18nFiles updateFiles: config.updateI18nFiles
}) })

View file

@ -7,14 +7,10 @@
"Notes" "Notes"
], ],
"website": "https://codimd.org", "website": "https://codimd.org",
"repository": "https://github.com/hackmdio/codimd", "repository": "https://github.com/codimd/server",
"logo": "https://github.com/hackmdio/codimd/raw/master/public/codimd-icon-1024.png", "logo": "https://github.com/codimd/server/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"
@ -23,137 +19,129 @@
"description": "Specify database type. See sequelize available databases. Default using postgres", "description": "Specify database type. See sequelize available databases. Default using postgres",
"value": "postgres" "value": "postgres"
}, },
"HMD_SESSION_SECRET": { "CMD_SESSION_SECRET": {
"description": "Secret used to secure session cookies.", "description": "Secret used to secure session cookies.",
"required": false "required": false
}, },
"HMD_HSTS_ENABLE": { "CMD_HSTS_ENABLE": {
"description": "whether to also use HSTS if HTTPS is enabled", "description": "whether to also use HSTS if HTTPS is enabled",
"required": false "required": false
}, },
"HMD_HSTS_MAX_AGE": { "CMD_HSTS_MAX_AGE": {
"description": "max duration, in seconds, to tell clients to keep HSTS status", "description": "max duration, in seconds, to tell clients to keep HSTS status",
"required": false "required": false
}, },
"HMD_HSTS_INCLUDE_SUBDOMAINS": { "CMD_HSTS_INCLUDE_SUBDOMAINS": {
"description": "whether to tell clients to also regard subdomains as HSTS hosts", "description": "whether to tell clients to also regard subdomains as HSTS hosts",
"required": false "required": false
}, },
"HMD_HSTS_PRELOAD": { "CMD_HSTS_PRELOAD": {
"description": "whether to allow at all adding of the site to HSTS preloads (e.g. in browsers)", "description": "whether to allow at all adding of the site to HSTS preloads (e.g. in browsers)",
"required": false "required": false
}, },
"HMD_DOMAIN": { "CMD_DOMAIN": {
"description": "domain name", "description": "domain name",
"required": false "required": false
}, },
"HMD_URL_PATH": { "CMD_URL_PATH": {
"description": "sub url path, like `www.example.com/<URL_PATH>`", "description": "sub url path, like `www.example.com/<URL_PATH>`",
"required": false "required": false
}, },
"HMD_ALLOW_ORIGIN": { "CMD_ALLOW_ORIGIN": {
"description": "domain name whitelist (use comma to separate)", "description": "domain name whitelist (use comma to separate)",
"required": false, "required": false,
"value": "localhost" "value": "localhost"
}, },
"HMD_PROTOCOL_USESSL": { "CMD_PROTOCOL_USESSL": {
"description": "set to use ssl protocol for resources path (only applied when domain is set)", "description": "set to use ssl protocol for resources path (only applied when domain is set)",
"required": false "required": false
}, },
"HMD_URL_ADDPORT": { "CMD_URL_ADDPORT": {
"description": "set to add port on callback url (port 80 or 443 won't applied) (only applied when domain is set)", "description": "set to add port on callback url (port 80 or 443 won't applied) (only applied when domain is set)",
"required": false "required": false
}, },
"HMD_FACEBOOK_CLIENTID": { "CMD_FACEBOOK_CLIENTID": {
"description": "Facebook API client id", "description": "Facebook API client id",
"required": false "required": false
}, },
"HMD_FACEBOOK_CLIENTSECRET": { "CMD_FACEBOOK_CLIENTSECRET": {
"description": "Facebook API client secret", "description": "Facebook API client secret",
"required": false "required": false
}, },
"HMD_TWITTER_CONSUMERKEY": { "CMD_TWITTER_CONSUMERKEY": {
"description": "Twitter API consumer key", "description": "Twitter API consumer key",
"required": false "required": false
}, },
"HMD_TWITTER_CONSUMERSECRET": { "CMD_TWITTER_CONSUMERSECRET": {
"description": "Twitter API consumer secret", "description": "Twitter API consumer secret",
"required": false "required": false
}, },
"HMD_GITHUB_CLIENTID": { "CMD_GITHUB_CLIENTID": {
"description": "GitHub API client id", "description": "GitHub API client id",
"required": false "required": false
}, },
"HMD_GITHUB_CLIENTSECRET": { "CMD_GITHUB_CLIENTSECRET": {
"description": "GitHub API client secret", "description": "GitHub API client secret",
"required": false "required": false
}, },
"HMD_GITLAB_BASEURL": { "CMD_GITLAB_BASEURL": {
"description": "GitLab authentication endpoint, set to use other endpoint than GitLab.com (optional)", "description": "GitLab authentication endpoint, set to use other endpoint than GitLab.com (optional)",
"required": false "required": false
}, },
"HMD_GITLAB_CLIENTID": { "CMD_GITLAB_CLIENTID": {
"description": "GitLab API client id", "description": "GitLab API client id",
"required": false "required": false
}, },
"HMD_GITLAB_CLIENTSECRET": { "CMD_GITLAB_CLIENTSECRET": {
"description": "GitLab API client secret", "description": "GitLab API client secret",
"required": false "required": false
}, },
"HMD_GITLAB_SCOPE": { "CMD_GITLAB_SCOPE": {
"description": "GitLab API client scope (optional)", "description": "GitLab API client scope (optional)",
"required": false "required": false
}, },
"HMD_MATTERMOST_BASEURL": { "CMD_MATTERMOST_BASEURL": {
"description": "Mattermost authentication endpoint", "description": "Mattermost authentication endpoint",
"required": false "required": false
}, },
"HMD_MATTERMOST_CLIENTID": { "CMD_MATTERMOST_CLIENTID": {
"description": "Mattermost API client id", "description": "Mattermost API client id",
"required": false "required": false
}, },
"HMD_MATTERMOST_CLIENTSECRET": { "CMD_MATTERMOST_CLIENTSECRET": {
"description": "Mattermost API client secret", "description": "Mattermost API client secret",
"required": false "required": false
}, },
"HMD_DROPBOX_CLIENTID": { "CMD_DROPBOX_CLIENTID": {
"description": "Dropbox API client id", "description": "Dropbox API client id",
"required": false "required": false
}, },
"HMD_DROPBOX_CLIENTSECRET": { "CMD_DROPBOX_CLIENTSECRET": {
"description": "Dropbox API client secret", "description": "Dropbox API client secret",
"required": false "required": false
}, },
"HMD_DROPBOX_APP_KEY": { "CMD_DROPBOX_APP_KEY": {
"description": "Dropbox app key (for import/export)", "description": "Dropbox app key (for import/export)",
"required": false "required": false
}, },
"HMD_GOOGLE_CLIENTID": { "CMD_GOOGLE_CLIENTID": {
"description": "Google API client id", "description": "Google API client id",
"required": false "required": false
}, },
"HMD_GOOGLE_CLIENTSECRET": { "CMD_GOOGLE_CLIENTSECRET": {
"description": "Google API client secret", "description": "Google API client secret",
"required": false "required": false
}, },
"HMD_IMGUR_CLIENTID": { "CMD_IMGUR_CLIENTID": {
"description": "Imgur API client id", "description": "Imgur API client id",
"required": false "required": false
}, },
"HMD_ALLOW_PDF_EXPORT": { "CMD_ALLOW_PDF_EXPORT": {
"description": "Enable or disable PDF exports", "description": "Enable or disable PDF exports",
"required": false "required": false
} }
}, },
"addons": [ "addons": [
"heroku-postgresql" "heroku-postgresql"
],
"buildpacks": [
{
"url": "https://github.com/alex88/heroku-buildpack-vips"
},
{
"url": "https://github.com/heroku/heroku-buildpack-nodejs"
}
] ]
} }

View file

@ -2,9 +2,7 @@
set -e set -e
if [ "$BUILD_ASSETS" = true ]; then cat << EOF > .sequelizerc
# setup config files
cat << EOF > .sequelizerc
var path = require('path'); var path = require('path');
module.exports = { module.exports = {
@ -17,7 +15,7 @@ module.exports = {
EOF EOF
cat << EOF > config.json cat << EOF > config.json
{ {
"production": { "production": {
@ -25,7 +23,3 @@ EOF
} }
EOF EOF
# build app
npm run build
fi

View file

@ -36,7 +36,7 @@ cat << EOF
Edit the following config file to setup CodiMD server and client. Edit the following config file to setup CodiMD server and client.
Read more info at https://github.com/hackmdio/codimd#configuration-files Read more info at https://github.com/codimd/server#configuration-files
* config.json -- CodiMD config * config.json -- CodiMD config
* .sequelizerc -- db config * .sequelizerc -- db config

View file

@ -93,6 +93,7 @@
"idpCert": "change: certificate file path of IdP in PEM format", "idpCert": "change: certificate file path of IdP in PEM format",
"issuer": "change or delete: identity of the service provider (default: serverurl)", "issuer": "change or delete: identity of the service provider (default: serverurl)",
"identifierFormat": "change or delete: name identifier format (default: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress')", "identifierFormat": "change or delete: name identifier format (default: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress')",
"disableRequestedAuthnContext": "change or delete: true to allow any authentication method, false restricts to password authentication method (default: false)",
"groupAttribute": "change or delete: attribute name for group list (ex: memberOf)", "groupAttribute": "change or delete: attribute name for group list (ex: memberOf)",
"requiredGroups": [ "change or delete: group names that allowed" ], "requiredGroups": [ "change or delete: group names that allowed" ],
"externalGroups": [ "change or delete: group names that not allowed" ], "externalGroups": [ "change or delete: group names that not allowed" ],

View file

@ -0,0 +1,153 @@
Configuration Using Config file
===
You can choose to configure CodiMD with either a config file or with
[environment variables](configuration-env-vars.md). The config file is processed
in [`lib/config/index.js`](../lib/config/index.js) - so this is the first
place to look if anything is missing not obvious from this document. The
default values are defined in [`lib/config/default.js`](../lib/config/default.js),
in case you wonder if you even need to override it.
Environment variables take precedence over configurations from the config files.
To get started, it is a good idea to take the `config.json.example` and copy it
to `config.json` before filling in your own details.
## Node.JS
| variables | example values | description |
| --------- | ------ | ----------- |
| `debug` | `true` or `false` | set debug mode, show more logs |
## CodiMD basics
| variables | example values | description |
| --------- | ------ | ----------- |
| `allowPDFExport` | `true` | Whether or not PDF export is offered. |
| `db` | `{ "dialect": "sqlite", "storage": "./db.codimd.sqlite" }` | set the db configs, [see more here](http://sequelize.readthedocs.org/en/latest/api/sequelize/) |
| `dbURL` | `mysql://localhost:3306/database` | set the db URL; if set, then db config (below) won't be applied |
| `forbiddenNoteIDs` | `['robots.txt']` | disallow creation of notes, even if `allowFreeUrl` is `true` |
| `loglevel` | `info` | Defines what kind of logs are provided to stdout. |
| `imageUploadType` | `imgur`, `s3`, `minio`, `azure`, `lutim` or `filesystem`(default) | Where to upload images. For S3, see our Image Upload Guides for [S3](guides/s3-image-upload.md) or [Minio](guides/minio-image-upload.md)|
| `sourceURL` | `https://github.com/codimd/server/tree/<current commit>` | Provides the link to the source code of CodiMD on the entry page (Please, make sure you change this when you run a modified version) |
| `staticCacheTime` | `1 * 24 * 60 * 60 * 1000` | static file cache time |
| `heartbeatInterval` | `5000` | socket.io heartbeat interval |
| `heartbeatTimeout` | `10000` | socket.io heartbeat timeout |
| `documentMaxLength` | `100000` | note max length |
## CodiMD paths stuff
these are rarely used for various reasons.
| variables | example values | description |
| --------- | ------ | ----------- |
| `defaultNotePath` | `./public/default.md` | default note file path<sup>1</sup>, empty notes will be created with this template. |
| `dhParamPath` | `./cert/dhparam.pem` | SSL dhparam path<sup>1</sup> (only need when you set `useSSL`) |
| `sslCAPath` | `['./cert/COMODORSAAddTrustCA.crt']` | SSL ca chain<sup>1</sup> (only need when you set `useSSL`) |
| `sslCertPath` | `./cert/codimd_io.crt` | SSL cert path<sup>1</sup> (only need when you set `useSSL`) |
| `sslKeyPath` | `./cert/client.key` | SSL key path<sup>1</sup> (only need when you set `useSSL`) |
| `tmpPath` | `./tmp/` | temp directory path<sup>1</sup> |
| `docsPath` | `./public/docs` | docs directory path<sup>1</sup> |
| `viewPath` | `./public/views` | template directory path<sup>1</sup> |
| `uploadsPath` | `./public/uploads` | uploads directory<sup>1</sup> - needs to be persistent when you use imageUploadType `filesystem` |
## CodiMD Location
| variables | example values | description |
| --------- | ------ | ----------- |
| `domain` | `localhost` | domain name |
| `urlPath` | `codimd` | sub URL path, like `www.example.com/<urlpath>` |
| `host` | `localhost` | interface/ip to listen on |
| `port` | `80` | port to listen on |
| `path` | `/var/run/codimd.sock` | path to UNIX domain socket to listen on (if specified, `host` and `port` are ignored) |
| `protocolUseSSL` | `true` or `false` | set to use SSL protocol for resources path (only applied when domain is set) |
| `useSSL` | `true` or `false` | set to use SSL server (if `true`, will auto turn on `protocolUseSSL`) |
| `urlAddPort` | `true` or `false` | set to add port on callback URL (ports `80` or `443` won't be applied) (only applied when domain is set) |
| `allowOrigin` | `['localhost']` | domain name whitelist |
## CSP and HSTS
| variables | example values | description |
| --------- | ------ | ----------- |
| `hsts` | `{"enable": true, "maxAgeSeconds": 31536000, "includeSubdomains": true, "preload": true}` | [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) options to use with HTTPS (default is the example value, max age is a year) |
| `csp` | `{"enable": true, "directives": {"scriptSrc": "trustworthy-scripts.example.com"}, "upgradeInsecureRequests": "auto", "addDefaults": true}` | Configures [Content Security Policy](https://helmetjs.github.io/docs/csp/). Directives are passed to Helmet - see [their documentation](https://helmetjs.github.io/docs/csp/) for more information on the format. Some defaults are added to the configured values so that the application doesn't break. To disable this behaviour, set `addDefaults` to `false`. Further, if `usecdn` is on, some CDN locations are allowed too. By default (`auto`), insecure (HTTP) requests are upgraded to HTTPS via CSP if `useSSL` is on. To change this behaviour, set `upgradeInsecureRequests` to either `true` or `false`. |
## Privacy and External Requests
| variables | example values | description |
| --------- | ------ | ----------- |
| `allowGravatar` | `true` or `false` | set to `false` to disable gravatar as profile picture source on your instance |
| `useCDN` | `true` or `false` | set to use CDN resources or not (default is `true`) |
## Users and Privileges
| variables | example values | description |
| --------- | ------ | ----------- |
| `allowAnonymous` | `true` or `false` | set to allow anonymous usage (default is `true`) |
| `allowAnonymousEdits` | `true` or `false` | if `allowAnonymous` is `true`: allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`) |
| `allowFreeURL` | `true` or `false` | set to allow new note creation by accessing a nonexistent note URL |
| `defaultPermission` | `freely`, `editable`, `limited`, `locked`, `protected` or `private` | set notes default permission (only applied on signed users) |
| `sessionName` | `connect.sid` | cookie session name |
| `sessionLife` | `14 * 24 * 60 * 60 * 1000` | cookie session life |
| `sessionSecret` | `secret` | cookie session secret | If none is set, one will randomly generated on each startup, meaning all your users will be logged out. |
## Login methods
Most of these have never been documented for the config.json, feel free to expand these
### Email (local account)
| variables | example values | description |
| --------- | ------ | ----------- |
| `email` | `true` or `false` | set to allow email signin |
| `allowEmailRegister` | `true` or `false` | set to allow email register (only applied when email is set, default is `true`. Note `bin/manage_users` might help you if registration is `false`.) |
### Dropbox Login
### Facebook Login
### GitHub Login
### GitLab Login
### Google Login
### LDAP Login
### Mattermost Login
### OAuth2 Login
| variables | example values | description |
| --------- | ------ | ----------- |
| `oauth2` | `{baseURL: ..., userProfileURL: ..., userProfileUsernameAttr: ..., userProfileDisplayNameAttr: ..., userProfileEmailAttr: ..., tokenURL: ..., authorizationURL: ..., clientID: ..., clientSecret: ...}` | An object detailing your OAuth2 provider. Refer to the [Mattermost](guides/auth/mattermost-self-hosted.md) or [Nextcloud](guides/auth/nextcloud.md) examples for more details!|
### SAML Login
### Twitter Login
## Upload Storage
Most of these have never been documented for the config.json, feel free to expand these
### Amazon S3
| variables | example values | description |
| --------- | ------ | ----------- |
| `s3` | `{ "accessKeyId": "YOUR_S3_ACCESS_KEY_ID", "secretAccessKey": "YOUR_S3_ACCESS_KEY", "region": "YOUR_S3_REGION" }` | When `imageuploadtype` be set to `s3`, you would also need to setup this key, check our [S3 Image Upload Guide](guides/s3-image-upload.md) |
| `s3bucket` | `YOUR_S3_BUCKET_NAME` | bucket name when `imageUploadType` is set to `s3` or `minio` |
### Azure Blob Storage
### imgur
### Minio
| variables | example values | description |
| --------- | ------ | ----------- |
| `minio` | `{ "accessKey": "YOUR_MINIO_ACCESS_KEY", "secretKey": "YOUR_MINIO_SECRET_KEY", "endpoint": "YOUR_MINIO_HOST", port: 9000, secure: true }` | When `imageUploadType` is set to `minio`, you need to set this key. Also check out our [Minio Image Upload Guide](guides/minio-image-upload.md) |
### Lutim
| variables | example values | description |
| --------- | ------ | ----------- |
|`lutim`| `{"url": "YOUR_LUTIM_URL"}`| When `imageUploadType` is set to `lutim`, you can setup the lutim url|
<sup>1</sup>: relative paths are based on CodiMD's base directory

View file

@ -0,0 +1,255 @@
Configuration Using Environment variables
===
You can choose to configure CodiMD with either a
[config file](configuration-config-file.md) or with environment variables.
Environment variables are processed in
[`lib/config/environment.js`](../lib/config/environment.js) - so this is the first
place to look if anything is missing not obvious from this document. The
default values are defined in [`lib/config/default.js`](../lib/config/default.js),
in case you wonder if you even need to override it.
Environment variables take precedence over configurations from the config files.
They generally start with `CMD_` for our own options, but we also list
node-specific options you can configure this way.
## Node.JS
| variable | example value | description |
| -------- | ------------- | ----------- |
| `NODE_ENV` | `production` or `development` | set current environment (will apply corresponding settings in the `config.json`) |
| `DEBUG` | `true` or `false` | set debug mode; show more logs |
## CodiMD basics
defaultNotePath can't be set from env-vars
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_ALLOW_PDF_EXPORT` | `true` or `false` | Enable or disable PDF exports |
| `CMD_CONFIG_FILE` | `/path/to/config.json` | optional override for the path to CodiMD's config file |
| `CMD_DB_URL` | `mysql://localhost:3306/database` | set the database URL |
| `CMD_LOGLEVEL` | `info`, `debug` ... | Defines what kind of logs are provided to stdout. |
| `CMD_FORBIDDEN_NOTE_IDS` | `'robots.txt'` | disallow creation of notes, even if `CMD_ALLOW_FREEURL` is `true` |
| `CMD_IMAGE_UPLOAD_TYPE` | `imgur`, `s3`, `minio`, `lutim` or `filesystem` | Where to upload images. For S3, see our Image Upload Guides for [S3](guides/s3-image-upload.md) or [Minio](guides/minio-image-upload.md), also there's a whole section on their respective env vars below. |
| `CMD_SOURCE_URL` | `https://github.com/codimd/server/tree/<current commit>` | Provides the link to the source code of CodiMD on the entry page (Please, make sure you change this when you run a modified version) |
## CodiMD Location
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_DOMAIN` | `codimd.org` | domain name |
| `CMD_URL_PATH` | `codimd` | If CodiMD is run from a subdirectory like `www.example.com/<urlpath>` |
| `CMD_HOST` | `localhost` | interface/ip to listen on |
| `CMD_PORT` | `80` | port to listen on |
| `CMD_PATH` | `/var/run/codimd.sock` | path to UNIX domain socket to listen on (if specified, `CMD_HOST` and `CMD_PORT` are ignored) |
| `CMD_PROTOCOL_USESSL` | `true` or `false` | set to use SSL protocol for resources path (only applied when domain is set) |
| `CMD_URL_ADDPORT` | `true` or `false` | set to add port on callback URL (ports `80` or `443` won't be applied) (only applied when domain is set) |
| `CMD_ALLOW_ORIGIN` | `localhost, codimd.org` | domain name whitelist (use comma to separate) |
## CSP and HSTS
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_CSP_ENABLE` | `true` | whether to enable Content Security Policy (directives cannot be configured with environment variables) |
| `CMD_CSP_REPORTURI` | `https://<someid>.report-uri.com/r/d/csp/enforce` | Allows to add a URL for CSP reports in case of violations |
| `CMD_HSTS_ENABLE` | ` true` | set to enable [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) if HTTPS is also enabled (default is ` true`) |
| `CMD_HSTS_INCLUDE_SUBDOMAINS` | `true` | set to include subdomains in HSTS (default is `true`) |
| `CMD_HSTS_MAX_AGE` | `31536000` | max duration in seconds to tell clients to keep HSTS status (default is a year) |
| `CMD_HSTS_PRELOAD` | `true` | whether to allow preloading of the site's HSTS status (e.g. into browsers) |
## Privacy and External Requests
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_ALLOW_GRAVATAR` | `true` or `false` | set to `false` to disable gravatar as profile picture source on your instance |
| `CMD_USECDN` | `true` or `false` | set to use CDN resources or not|
## Users and Privileges
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_ALLOW_ANONYMOUS` | `true` or `false` | set to allow anonymous usage (default is `true`) |
| `CMD_ALLOW_ANONYMOUS_EDITS` | `true` or `false` | if `allowAnonymous` is `true`, allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`) |
| `CMD_ALLOW_FREEURL` | `true` or `false` | set to allow new note creation by accessing a nonexistent note URL |
| `CMD_DEFAULT_PERMISSION` | `freely`, `editable`, `limited`, `locked` or `private` | set notes default permission (only applied on signed users) |
| `CMD_SESSION_LIFE` | `1209600000` | Session life time. (milliseconds) |
| `CMD_SESSION_SECRET` | no example | Secret used to sign the session cookie. If none is set, one will randomly generated on each startup, meaning all your users will be logged out. |
## Login methods
### Email (local account)
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_EMAIL` | `true` or `false` | set to allow email signin |
| `CMD_ALLOW_EMAIL_REGISTER` | `true` or `false` | set to allow email register (only applied when email is set, default is `true`. Note `bin/manage_users` might help you if registration is `false`.) |
### Dropbox Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_DROPBOX_CLIENTID` | no example | Dropbox API client id |
| `CMD_DROPBOX_CLIENTSECRET` | no example | Dropbox API client secret |
### Facebook Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_FACEBOOK_CLIENTID` | no example | Facebook API client id |
| `CMD_FACEBOOK_CLIENTSECRET` | no example | Facebook API client secret |
### GitHub Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_GITHUB_CLIENTID` | no example | GitHub API client id |
| `CMD_GITHUB_CLIENTSECRET` | no example | GitHub API client secret |
### GitLab Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_GITLAB_SCOPE` | `read_user` or `api` | GitLab API requested scope (default is `api`) (GitLab snippet import/export need `api` scope) |
| `CMD_GITLAB_BASEURL` | no example | GitLab authentication endpoint, set to use other endpoint than GitLab.com (optional) |
| `CMD_GITLAB_CLIENTID` | no example | GitLab API client id |
| `CMD_GITLAB_CLIENTSECRET` | no example | GitLab API client secret |
| `CMD_GITLAB_VERSION` | no example | GitLab API version (v3 or v4) |
### Google Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_GOOGLE_CLIENTID` | no example | Google API client id |
| `CMD_GOOGLE_CLIENTSECRET` | no example | Google API client secret |
### LDAP Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_LDAP_URL` | `ldap://example.com` | URL of LDAP server |
| `CMD_LDAP_BINDDN` | no example | bindDn for LDAP access |
| `CMD_LDAP_BINDCREDENTIALS` | no example | bindCredentials for LDAP access |
| `CMD_LDAP_SEARCHBASE` | `o=users,dc=example,dc=com` | LDAP directory to begin search from |
| `CMD_LDAP_SEARCHFILTER` | `(uid={{username}})` | LDAP filter to search with |
| `CMD_LDAP_SEARCHATTRIBUTES` | `displayName, mail` | LDAP attributes to search with (use comma to separate) |
| `CMD_LDAP_USERIDFIELD` | `uidNumber` or `uid` or `sAMAccountName` | The LDAP field which is used uniquely identify a user on CodiMD |
| `CMD_LDAP_USERNAMEFIELD` | Fallback to userid | The LDAP field which is used as the username on CodiMD |
| `CMD_LDAP_TLS_CA` | `server-cert.pem, root.pem` | Root CA for LDAP TLS in PEM format (use comma to separate) |
| `CMD_LDAP_PROVIDERNAME` | `My institution` | Optional name to be displayed at login form indicating the LDAP provider |
### Mattermost Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_MATTERMOST_BASEURL` | no example | Mattermost authentication endpoint for versions below 5.0. For Mattermost version 5.0 and above, see [guide](guides/auth/mattermost-self-hosted.md). |
| `CMD_MATTERMOST_CLIENTID` | no example | Mattermost API client id |
| `CMD_MATTERMOST_CLIENTSECRET` | no example | Mattermost API client secret |
### OAuth2 Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_OAUTH2_USER_PROFILE_URL` | `https://example.com` | where retrieve information about a user after succesful login. Needs to output JSON. (no default value) Refer to the [Mattermost](guides/auth/mattermost-self-hosted.md) or [Nextcloud](guides/auth/nextcloud.md) examples for more details on all of the `CMD_OAUTH2...` options. |
| `CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR` | `name` | where to find the username in the JSON from the user profile URL. (no default value)|
| `CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR` | `display-name` | where to find the display-name in the JSON from the user profile URL. (no default value) |
| `CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR` | `email` | where to find the email address in the JSON from the user profile URL. (no default value) |
| `CMD_OAUTH2_TOKEN_URL` | `https://example.com` | sometimes called token endpoint, please refer to the documentation of your OAuth2 provider (no default value) |
| `CMD_OAUTH2_AUTHORIZATION_URL` | `https://example.com` | authorization URL of your provider, please refer to the documentation of your OAuth2 provider (no default value) |
| `CMD_OAUTH2_CLIENT_ID` | `afae02fckafd...` | you will get this from your OAuth2 provider when you register CodiMD as OAuth2-client, (no default value) |
| `CMD_OAUTH2_CLIENT_SECRET` | `afae02fckafd...` | you will get this from your OAuth2 provider when you register CodiMD as OAuth2-client, (no default value) |
| `CMD_OAUTH2_PROVIDERNAME` | `My institution` | Optional name to be displayed at login form indicating the oAuth2 provider |
### SAML Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_SAML_IDPSSOURL` | `https://idp.example.com/sso` | authentication endpoint of IdP. for details, see [guide](guides/auth/saml-onelogin.md). |
| `CMD_SAML_IDPCERT` | `/path/to/cert.pem` | certificate file path of IdP in PEM format |
| `CMD_SAML_ISSUER` | no example | identity of the service provider (optional, default: serverurl)" |
| `CMD_SAML_DISABLEREQUESTEDAUTHNCONTEXT` | `true` or `false` | true to allow any authentication method, false restricts to password authentication (PasswordProtectedTransport) method (default: false) |
| `CMD_SAML_IDENTIFIERFORMAT` | no example | name identifier format (optional, default: `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`) |
| `CMD_SAML_GROUPATTRIBUTE` | `memberOf` | attribute name for group list (optional) |
| `CMD_SAML_REQUIREDGROUPS` | `codimd-users` | group names that allowed (use vertical bar to separate) (optional) |
| `CMD_SAML_EXTERNALGROUPS` | `Temporary-staff` | group names that not allowed (use vertical bar to separate) (optional) |
| `CMD_SAML_ATTRIBUTE_ID` | `sAMAccountName` | attribute map for `id` (optional, default: NameID of SAML response) |
| `CMD_SAML_ATTRIBUTE_USERNAME` | `mailNickname` | attribute map for `username` (optional, default: NameID of SAML response) |
| `CMD_SAML_ATTRIBUTE_EMAIL` | `mail` | attribute map for `email` (optional, default: NameID of SAML response if `CMD_SAML_IDENTIFIERFORMAT` is default) |
### Twitter Login
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_TWITTER_CONSUMERKEY` | no example | Twitter API consumer key |
| `CMD_TWITTER_CONSUMERSECRET` | no example | Twitter API consumer secret |
## Upload Storage
These are only relevant when they are also configured in sync with their
`CMD_IMAGE_UPLOAD_TYPE`. Also keep in mind, that `filesystem` is available, so
you don't have to use either of these.
### Amazon S3
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_S3_ACCESS_KEY_ID` | no example | AWS access key id |
| `CMD_S3_SECRET_ACCESS_KEY` | no example | AWS secret key |
| `CMD_S3_REGION` | `ap-northeast-1` | AWS S3 region |
| `CMD_S3_BUCKET` | no example | AWS S3 bucket name |
### Azure Blob Storage
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_AZURE_CONNECTION_STRING` | no example | Azure Blob Storage connection string |
| `CMD_AZURE_CONTAINER` | no example | Azure Blob Storage container name (automatically created if non existent) |
### imgur
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_IMGUR_CLIENTID` | no example | Imgur API client id |
### Minio
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_MINIO_ACCESS_KEY` | no example | Minio access key |
| `CMD_MINIO_SECRET_KEY` | no example | Minio secret key |
| `CMD_MINIO_ENDPOINT` | `minio.example.org` | Address of your Minio endpoint/instance |
| `CMD_MINIO_PORT` | `9000` | Port that is used for your Minio instance |
| `CMD_MINIO_SECURE` | `true` | If set to `true` HTTPS is used for Minio |
### Lutim
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_LUTIM_URL` | `https://framapic.org/` | When `CMD_IMAGE_UPLOAD_TYPE` is set to `lutim`, you can setup the lutim url |
**Note:** *Due to the rename process we renamed all `HMD_`-prefix variables to be `CMD_`-prefixed. The old ones continue to work.*
**Note:** *relative paths are based on CodiMD's base directory*

View file

@ -0,0 +1,57 @@
Developer Notes
===
## Preparing for running the code
**Notice:** *There's [specialised instructions for docker](../setup/docker.md) or [heroku](../setup/heroku.md), if you prefer running code this way!*
1. Clone the repository with `git clone https://github.com/codimd/server.git codimd-server`
(cloning is the preferred way, but you can also download and unzip a release)
2. Enter the directory and run `bin/setup`, which will install npm dependencies
and create configs. The setup script is written in Bash, you would need bash
as a prerequisite.
3. Setup the [config file](../configuration-config-file.md) or set up
[environment variables](../configuration-env-vars.md).
## Running the Code
Now that everything is in place, we can start CodiMD:
4. `npm run build` will build the frontend bundle. It uses webpack to do that.
5. Run the server with `node app.js`
## Running the Code with Auto-Reload
The commands above are fine for production, but you're a developer and surely
you want to change things. You would need to restart both commands whenever you
change something. Luckily, you can run these commands that will automatically
rebuild the frontend or restart the server if necessary.
The commands will stay active in your terminal, so you will need multiple tabs
to run both at the same time.
4. Use `npm run dev` if you want webpack to continuously rebuild the frontend
code.
5. To auto-reload the server, the easiest method is to install [nodemon](https://www.npmjs.com/package/nodemon)
and run `nodemon --watch app.js --watch lib --watch locales app.js`.
## Structure
The repository contains two parts: a server (backend) and a client (frontend).
most of the server code is in `/lib` and most of the client code is in `public`.
```text
codimd-server/
├── docs/ --- documentation
├── lib/ --- server code
├── test/ --- test suite
└── public/ --- client code
├── css/ --- css styles
├── docs/ --- default documents
├── js/ --- js scripts
├── vendor/ --- vendor includes
└── views/ --- view templates
```

14
docs/dev/ot.md Normal file
View file

@ -0,0 +1,14 @@
Operational Transformation
===
From 0.3.2, we started supporting operational transformation.
It makes concurrent editing safe and will not break up other users' operations.
Additionally, now can show other clients' selections.
See more at [https://operational-transformation.github.io/](https://operational-transformation.github.io/)
And even more in this 2010 article series:
* https://drive.googleblog.com/2010/09/whats-different-about-new-google-docs_21.html
* https://drive.googleblog.com/2010/09/whats-different-about-new-google-docs_22.html
* https://drive.googleblog.com/2010/09/whats-different-about-new-google-docs.html

View file

@ -1,4 +1,11 @@
# Webpack Docs Webpack
===
Webpack is a JavaScript build system for frontend code. You can find out all
about it on [the webpack website](https://webpack.js.org/).
Here's how we're using it:
## `webpack.common.js` ## `webpack.common.js`
This file contains all common definition for chunks and plugins, that are needed by the whole app. This file contains all common definition for chunks and plugins, that are needed by the whole app.

View file

@ -1,27 +1,24 @@
Authentication guide - GitHub Authentication guide - GitHub
=== ===
***Note:** This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!* **Note:** *This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!*
1. Sign-in or sign-up for a GitHub account 1. Sign-in or sign-up for a GitHub account
2. Navigate to developer settings in your GitHub account [here](https://github.com/settings/developers) and select the "OAuth Apps" tab 2. Navigate to developer settings in your GitHub account [here](https://github.com/settings/developers) and select the "OAuth Apps" tab
3. Click on the **New OAuth App** button, to create a new OAuth App: 3. Click on the **New OAuth App** button, to create a new OAuth App:
![create-oauth-app](../../images/auth/create-oauth-app.png)
![create-oauth-app](../images/auth/create-oauth-app.png) 4. Fill out the new OAuth application registration form, and click **Register Application**
![register-oauth-application-form](../../images/auth/register-oauth-application-form.png)
4. Fill out the new OAuth application registration form, and click **Register Application** **Note:** *The callback URL is <your-codimd-url>/auth/github/callback*
![register-oauth-application-form](../images/auth/register-oauth-application-form.png) 5. After successfully registering the application, you'll receive the Client ID and Client Secret for the application
![application-page](../../images/auth/application-page.png)
*Note: The callback URL is <your-hackmd-url>/auth/github/callback*
5. After successfully registering the application, you'll receive the Client ID and Client Secret for the application
![application-page](../images/auth/application-page.png)
6. Add the Client ID and Client Secret to your config.json file or pass them as environment variables 6. Add the Client ID and Client Secret to your config.json file or pass them as environment variables
* config.json: * `config.json`:
````javascript ```js
{ {
"production": { "production": {
"github": { "github": {
@ -30,9 +27,9 @@ Authentication guide - GitHub
} }
} }
} }
```` ```
* environment variables: * environment variables:
```` ```sh
HMD_GITHUB_CLIENTID=3747d30eaccXXXXXXXXX CMD_GITHUB_CLIENTID=3747d30eaccXXXXXXXXX
HMD_GITHUB_CLIENTSECRET=2a8e682948eee0c580XXXXXXXXXXXXXXXXXXXXXX CMD_GITHUB_CLIENTSECRET=2a8e682948eee0c580XXXXXXXXXXXXXXXXXXXXXX
```` ````

View file

@ -1,24 +1,24 @@
# GitLab (self-hosted) GitLab (self-hosted)
=== ===
***Note:** This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!* **Note:** *This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!*
1. Sign in to your GitLab 1. Sign in to your GitLab
2. Navigate to the application management page at `https://your.gitlab.domain/admin/applications` (admin permissions required) 2. Navigate to the application management page at `https://your.gitlab.domain/admin/applications` (admin permissions required)
3. Click **New application** to create a new application and fill out the registration form: 3. Click **New application** to create a new application and fill out the registration form:
![New GitLab application](../images/auth/gitlab-new-application.png) ![New GitLab application](../../images/auth/gitlab-new-application.png)
4. Click **Submit** 4. Click **Submit**
5. In the list of applications select **HackMD**. Leave that site open to copy the application ID and secret in the next step. 5. In the list of applications select **HackMD**. Leave that site open to copy the application ID and secret in the next step.
![Application: HackMD](../images/auth/gitlab-application-details.png) ![Application: HackMD](../../images/auth/gitlab-application-details.png)
6. In the `docker-compose.yml` add the following environment variables to `app:` `environment:` 6. In the `docker-compose.yml` add the following environment variables to `app:` `environment:`
``` ```
- HMD_DOMAIN=your.hackmd.domain - HMD_DOMAIN=your.codimd.domain
- HMD_URL_ADDPORT=443 - HMD_URL_ADDPORT=443
- HMD_PROTOCOL_USESSL=true - HMD_PROTOCOL_USESSL=true
- HMD_GITLAB_BASEURL=https://your.gitlab.domain - HMD_GITLAB_BASEURL=https://your.gitlab.domain
@ -27,6 +27,6 @@
``` ```
7. Run `docker-compose up -d` to apply your settings. 7. Run `docker-compose up -d` to apply your settings.
8. Sign in to your HackMD using your GitLab ID: 8. Sign in to your CodiMD using your GitLab ID:
![Sign in via GitLab](../images/auth/gitlab-sign-in.png) ![Sign in via GitLab](../../images/auth/gitlab-sign-in.png)

View file

@ -1,7 +1,6 @@
AD LDAP auth AD LDAP auth
=== ===
To setup your CodiMD instance with Active Directory you need the following configs: To setup your CodiMD instance with Active Directory you need the following configs:
``` ```

View file

@ -1,33 +1,29 @@
Authentication guide - Mattermost (self-hosted) 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.* **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. 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 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` 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)
![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` 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 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)
![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)
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* *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 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)
![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 7. Add the Client ID and Client Secret to your config.json file or pass them as environment variables
* config.json: * `config.json`:
````javascript ```javascript
{ {
"production": { "production": {
"oauth2": { "oauth2": {
@ -43,9 +39,9 @@ This guide uses the generic OAuth2 module for compatibility with Mattermost vers
} }
} }
} }
```` ```
* environment variables: * environment variables:
```` ```sh
CMD_OAUTH2_BASEURL=https://your.mattermost.domain CMD_OAUTH2_BASEURL=https://your.mattermost.domain
CMD_OAUTH2_USER_PROFILE_URL=https://your.mattermost.domain/api/v4/users/me CMD_OAUTH2_USER_PROFILE_URL=https://your.mattermost.domain/api/v4/users/me
CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR=id CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR=id
@ -55,4 +51,4 @@ This guide uses the generic OAuth2 module for compatibility with Mattermost vers
CMD_OAUTH2_AUTHORIZATION_URL=https://your.mattermost.domain/oauth/authorize CMD_OAUTH2_AUTHORIZATION_URL=https://your.mattermost.domain/oauth/authorize
CMD_OAUTH2_CLIENT_ID=ii4p1u3jz7dXXXXXXXXXXXXXXX CMD_OAUTH2_CLIENT_ID=ii4p1u3jz7dXXXXXXXXXXXXXXX
CMD_OAUTH2_CLIENT_SECRET=mqzzx6fydbXXXXXXXXXXXXXXXX CMD_OAUTH2_CLIENT_SECRET=mqzzx6fydbXXXXXXXXXXXXXXXX
```` ```

View file

@ -9,15 +9,15 @@ This guide uses the generic OAuth2 module for compatibility with Nextcloud 13 an
2. Navigate to the OAuth integration settings: Profile Icon (top right) --> Settings 2. Navigate to the OAuth integration settings: Profile Icon (top right) --> Settings
Then choose Security Settings from the *Administration* part of the list - Don't confuse this with Personal Security Settings, where you would change your personal password! Then choose Security Settings from the *Administration* part of the list - Don't confuse this with Personal Security Settings, where you would change your personal password!
At the top there's OAuth 2.0-Clients. At the top there's OAuth 2.0-Clients.
![Where to find OAuth2 in Nextcloud](../images/auth/nextcloud-oauth2-1-settings.png) ![Where to find OAuth2 in Nextcloud](../../images/auth/nextcloud-oauth2-1-settings.png)
3. Add your CodiMD instance by giving it a *name* (perhaps CodiMD, but could be anything) and a *Redirection-URI*. The Redirection-URI will be `\<your-codimd-url\>/auth/oauth2/callback`. Click <kbd>Add</kbd>. 3. Add your CodiMD instance by giving it a *name* (perhaps CodiMD, but could be anything) and a *Redirection-URI*. The Redirection-URI will be `\<your-codimd-url\>/auth/oauth2/callback`. Click <kbd>Add</kbd>.
![Adding a client to Nextcloud](../images/auth/nextcloud-oauth2-2-client-add.png) ![Adding a client to Nextcloud](../../images/auth/nextcloud-oauth2-2-client-add.png)
4. You'll now see a line containing a *client identifier* and a *Secret*. 4. You'll now see a line containing a *client identifier* and a *Secret*.
![Successfully added OAuth2-client](../images/auth/nextcloud-oauth2-3-clientid-secret.png) ![Successfully added OAuth2-client](../../images/auth/nextcloud-oauth2-3-clientid-secret.png)
5. That's it for Nextcloud, the rest is configured in your CodiMD `config.json` or via the `CMD_` environment variables! 5. That's it for Nextcloud, the rest is configured in your CodiMD `config.json` or via the `CMD_` environment variables!

12
docs/guides/auth/oauth.md Normal file
View file

@ -0,0 +1,12 @@
# OAuth general information
| service | callback URL (after the server URL) |
| ------- | --------- |
| facebook | `/auth/facebook/callback` |
| twitter | `/auth/twitter/callback` |
| github | `/auth/github/callback` |
| gitlab | `/auth/gitlab/callback` |
| mattermost | `/auth/mattermost/callback` |
| dropbox | `/auth/dropbox/callback` |
| google | `/auth/google/callback` |
| saml | `/auth/saml/callback` |

View file

@ -1,40 +1,35 @@
Authentication guide - SAML (OneLogin) Authentication guide - SAML (OneLogin)
=== ===
***Note:** This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!* **Note:** *This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!*
1. Sign-in or sign-up for an OneLogin account. (available free trial for 2 weeks) 1. Sign-in or sign-up for an OneLogin account. (available free trial for 2 weeks)
2. Go to the administration page. 2. Go to the administration page.
3. Select the **APPS** menu and click on the **Add Apps**. 3. Select the **APPS** menu and click on the **Add Apps**.
![onelogin-add-app](../../images/auth/onelogin-add-app.png)
![onelogin-add-app](../images/auth/onelogin-add-app.png) 4. Find "SAML Test Connector (SP)" for template of settings and select it.
![onelogin-select-template](../../images/auth/onelogin-select-template.png)
4. Find "SAML Test Connector (SP)" for template of settings and select it. 5. Edit display name and icons for OneLogin dashboard as you want, and click **SAVE**.
![onelogin-edit-app-name](../../images/auth/onelogin-edit-app-name.png)
![onelogin-select-template](../images/auth/onelogin-select-template.png)
5. Edit display name and icons for OneLogin dashboard as you want, and click **SAVE**.
![onelogin-edit-app-name](../images/auth/onelogin-edit-app-name.png)
6. After that other tabs will appear, click the **Configuration**, and fill out the below items, and click **SAVE**. 6. After that other tabs will appear, click the **Configuration**, and fill out the below items, and click **SAVE**.
* RelayState: The base URL of your hackmd, which is issuer. (last slash is not needed) * RelayState: The base URL of your CodiMD, which is issuer. (last slash is not needed)
* ACS (Consumer) URL Validator: The callback URL of your hackmd. (serverurl + /auth/saml/callback) * ACS (Consumer) URL Validator: The callback URL of your CodiMD. (serverurl + /auth/saml/callback)
* ACS (Consumer) URL: same as above. * ACS (Consumer) URL: same as above.
* Login URL: login URL(SAML requester) of your hackmd. (serverurl + /auth/saml) * Login URL: login URL(SAML requester) of your CopiMD. (serverurl + /auth/saml)
![onelogin-edit-sp-metadata](../../images/auth/onelogin-edit-sp-metadata.png)
![onelogin-edit-sp-metadata](../images/auth/onelogin-edit-sp-metadata.png)
7. The registration is completed. Next, click **SSO** and copy or download the items below. 7. The registration is completed. Next, click **SSO** and copy or download the items below.
* X.509 Certificate: Click **View Details** and **DOWNLOAD** or copy the content of certificate ....(A) * X.509 Certificate: Click **View Details** and **DOWNLOAD** or copy the content of certificate ....(A)
* SAML 2.0 Endpoint (HTTP): Copy the URL ....(B) * SAML 2.0 Endpoint (HTTP): Copy the URL ....(B)
![onelogin-copy-idp-metadata](../../images/auth/onelogin-copy-idp-metadata.png)
![onelogin-copy-idp-metadata](../images/auth/onelogin-copy-idp-metadata.png) 8. In your CodiMD server, create IdP certificate file from (A)
8. In your hackmd server, create IdP certificate file from (A)
9. Add the IdP URL (B) and the Idp certificate file path to your config.json file or pass them as environment variables. 9. Add the IdP URL (B) and the Idp certificate file path to your config.json file or pass them as environment variables.
* config.json: * `config.json`:
````javascript ```javascript
{ {
"production": { "production": {
"saml": { "saml": {
@ -43,12 +38,11 @@ Authentication guide - SAML (OneLogin)
} }
} }
} }
```` ```
* environment variables * environment variables
```` ```sh
HMD_SAML_IDPSSOURL=https://*******.onelogin.com/trust/saml2/http-post/sso/****** CMD_SAML_IDPSSOURL=https://*******.onelogin.com/trust/saml2/http-post/sso/******
HMD_SAML_IDPCERT=/path/to/idp_cert.pem CMD_SAML_IDPCERT=/path/to/idp_cert.pem
```` ```
10. Try sign-in with SAML from your hackmd sign-in button or OneLogin dashboard (like the screenshot below). 10. Try sign-in with SAML from your CodiMD sign-in button or OneLogin dashboard (like the screenshot below).
![onelogin-use-dashboard](../../images/auth/onelogin-use-dashboard.png)
![onelogin-use-dashboard](../images/auth/onelogin-use-dashboard.png)

View file

@ -1,7 +1,7 @@
Authentication guide - SAML Authentication guide - SAML
=== ===
***Note:** This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!* **Note:** *This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!*
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. 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.
@ -9,36 +9,36 @@ The basic procedure is the same as the case of OneLogin which is mentioned in [O
* {{your-serverurl}}/auth/saml/metadata * {{your-serverurl}}/auth/saml/metadata
* _Note: If not accessible from IdP, download to local once and upload to IdP._ * _Note: If not accessible from IdP, download to local once and upload to IdP._
* Change the value of `issuer`, `identifierFormat` to match your IdP. * Change the value of `issuer`, `identifierFormat` to match your IdP.
* `issuer`: A unique id to identify the application to the IdP, which is the base URL of your HackMD as default * `issuer`: A unique id to identify the application to the IdP, which is the base URL of your CodiMD as default
* `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. * `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.
* urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress (default) * urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress (default)
* urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified * urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
* config.json: * `config.json`:
````javascript ```javascript
{ {
"production": { "production": {
"saml": { "saml": {
/* omitted */ /* omitted */
"issuer": "myhackmd" "issuer": "mycodimd"
"identifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" "identifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
} }
} }
} }
```` ```
* environment variables * environment variables
```` ```
HMD_SAML_ISSUER=myhackmd CMD_SAML_ISSUER=mycodimd
HMD_SAML_IDENTIFIERFORMAT=urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified CMD_SAML_IDENTIFIERFORMAT=urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
```` ```
* Change mapping of attribute names to customize the displaying user name and email address to match your IdP. * Change mapping of attribute names to customize the displaying user name and email address to match your IdP.
* `attribute`: A dictionary to map attribute names * `attribute`: A dictionary to map attribute names
* `attribute.id`: A primary key of user table for your HackMD * `attribute.id`: A primary key of user table for your CodiMD
* `attribute.username`: Attribute name of displaying user name on HackMD * `attribute.username`: Attribute name of displaying user name on CodiMD
* `attribute.email`: Attribute name of email address, which will be also used for Gravatar * `attribute.email`: Attribute name of email address, which will be also used for Gravatar
* _Note: Default value of all attributes is NameID of SAML response, which is email address if `identifierFormat` is default._ * _Note: Default value of all attributes is NameID of SAML response, which is email address if `identifierFormat` is default._
* config.json: * `config.json`:
````javascript ```javascript
{ {
"production": { "production": {
"saml": { "saml": {
@ -51,35 +51,35 @@ The basic procedure is the same as the case of OneLogin which is mentioned in [O
} }
} }
} }
```` ```
* environment variables * environment variables
```` ```sh
HMD_SAML_ATTRIBUTE_ID=sAMAccountName CMD_SAML_ATTRIBUTE_ID=sAMAccountName
HMD_SAML_ATTRIBUTE_USERNAME=nickName CMD_SAML_ATTRIBUTE_USERNAME=nickName
HMD_SAML_ATTRIBUTE_EMAIL=mail CMD_SAML_ATTRIBUTE_EMAIL=mail
```` ```
* If you want to control permission by group membership, add group attribute name and required group (allowed) or external group (not allowed). * If you want to control permission by group membership, add group attribute name and required group (allowed) or external group (not allowed).
* `groupAttribute`: An attribute name of group membership * `groupAttribute`: An attribute name of group membership
* `requiredGroups`: Group names array for allowed access to HackMD. Use vertical bar to separate for environment variables. * `requiredGroups`: Group names array for allowed access to CodiMD. Use vertical bar to separate for environment variables.
* `externalGroups`: Group names array for not allowed access to HackMD. Use vertical bar to separate for environment variables. * `externalGroups`: Group names array for not allowed access to CodiMD. Use vertical bar to separate for environment variables.
* _Note: Evaluates `externalGroups` first_ * _Note: Evaluates `externalGroups` first_
* config.json: * `config.json`:
````javascript ```javascript
{ {
"production": { "production": {
"saml": { "saml": {
/* omitted */ /* omitted */
"groupAttribute": "memberOf", "groupAttribute": "memberOf",
"requiredGroups": [ "hackmd-users", "board-members" ], "requiredGroups": [ "codimd-users", "board-members" ],
"externalGroups": [ "temporary-staff" ] "externalGroups": [ "temporary-staff" ]
} }
} }
} }
```` ```
* environment variables * environment variables
```` ```sh
HMD_SAML_GROUPATTRIBUTE=memberOf CMD_SAML_GROUPATTRIBUTE=memberOf
HMD_SAML_REQUIREDGROUPS=hackmd-users|board-members CMD_SAML_REQUIREDGROUPS=codimd-users|board-members
HMD_SAML_EXTERNALGROUPS=temporary-staff CMD_SAML_EXTERNALGROUPS=temporary-staff
```` ```

View file

@ -1,33 +1,29 @@
Authentication guide - Twitter Authentication guide - Twitter
=== ===
***Note:** This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!* **Note:** *This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!*
1. Sign-in or sign-up for a Twitter account 1. Sign-in or sign-up for a Twitter account
2. Go to the Twitter Application management page [here](https://apps.twitter.com/) 2. Go to the Twitter Application management page [here](https://apps.twitter.com/)
3. Click on the **Create New App** button to create a new Twitter app: 3. Click on the **Create New App** button to create a new Twitter app:
![create-twitter-app](../../images/auth/create-twitter-app.png)
![create-twitter-app](../images/auth/create-twitter-app.png) 4. Fill out the create application form, check the developer agreement box, and click **Create Your Twitter Application**
![register-twitter-application](../../images/auth/register-twitter-application.png)
4. Fill out the create application form, check the developer agreement box, and click **Create Your Twitter Application** *Note: you may have to register your phone number with Twitter to create a Twitter application*
![register-twitter-application](../images/auth/register-twitter-application.png) To do this Click your profile icon --> Settings and privacy --> Mobile --> Select Country/region --> Enter phone number --> Click Continue
*Note: you may have to register your phone number with Twitter to create a Twitter application* 5. After you receive confirmation that the Twitter application was created, click **Keys and Access Tokens**
![twitter-app-confirmation](../../images/auth/twitter-app-confirmation.png)
To do this Click your profile icon --> Settings and privacy --> Mobile --> Select Country/region --> Enter phone number --> Click Continue 6. Obtain your Twitter Consumer Key and Consumer Secret
![twitter-app-keys](../../images/auth/twitter-app-keys.png)
5. After you receive confirmation that the Twitter application was created, click **Keys and Access Tokens** 7. Add your Consumer Key and Consumer Secret to your `config.json` file or pass them as environment variables:
* `config.json`:
![twitter-app-confirmation](../images/auth/twitter-app-confirmation.png) ```javascript
6. Obtain your Twitter Consumer Key and Consumer Secret
![twitter-app-keys](../images/auth/twitter-app-keys.png)
7. Add your Consumer Key and Consumer Secret to your config.json file or pass them as environment variables:
* config.json:
````javascript
{ {
"production": { "production": {
"twitter": { "twitter": {
@ -36,9 +32,9 @@ To do this Click your profile icon --> Settings and privacy --> Mobile --> Sele
} }
} }
} }
```` ```
* environment variables: * environment variables:
```` ```sh
HMD_TWITTER_CONSUMERKEY=esTCJFXXXXXXXXXXXXXXXXXXX CMD_TWITTER_CONSUMERKEY=esTCJFXXXXXXXXXXXXXXXXXXX
HMD_TWITTER_CONSUMERSECRET=zpCs4tU86pRVXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX CMD_TWITTER_CONSUMERSECRET=zpCs4tU86pRVXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```` ```

View file

@ -12,7 +12,7 @@ require some creativity to work properly in your case. When I wrote this guide,
[Etherpad 1.7.0] and [CodiMD 1.2.1]. Good luck! [Etherpad 1.7.0] and [CodiMD 1.2.1]. Good luck!
[Etherpad 1.7.0]: https://github.com/ether/etherpad-lite/tree/1.7.0 [Etherpad 1.7.0]: https://github.com/ether/etherpad-lite/tree/1.7.0
[CodiMD 1.2.1]: https://github.com/hackmdio/codimd/tree/1.2.1 [CodiMD 1.2.1]: https://github.com/codimd/server/tree/1.2.1
## 0. Requirements ## 0. Requirements
@ -21,7 +21,7 @@ require some creativity to work properly in your case. When I wrote this guide,
- running CodiMD server - running CodiMD server
- [codimd-cli] - [codimd-cli]
[codimd-cli]: https://github.com/hackmdio/codimd-cli/blob/master/bin/codimd [codimd-cli]: https://github.com/codimd/cli/blob/master/bin/codimd
## 1. Retrieve the list of pads ## 1. Retrieve the list of pads
@ -56,8 +56,8 @@ configuration settings `ETHERPAD_SERVER` and `CODIMD_SERVER`.
# Description: Migrate pads from etherpad to codimd # Description: Migrate pads from etherpad to codimd
# Author: Daan Sprenkels <hello@dsprenkels.com> # Author: Daan Sprenkels <hello@dsprenkels.com>
# This script uses the codimd command line script[1] to import a list of pads from # This script uses the codimd command line script[1] to import a list of pads from
# [1]: https://github.com/hackmdio/codimd-cli/blob/master/bin/codimd # [1]: https://github.com/codimd/cli/blob/master/bin/codimd
# The base url to where etherpad is hosted # The base url to where etherpad is hosted
ETHERPAD_SERVER="https://etherpad.example.com" ETHERPAD_SERVER="https://etherpad.example.com"
@ -80,7 +80,7 @@ for PAD_NAME in $1; do
# Download the pad # Download the pad
PAD_FILE="$(mktemp)" PAD_FILE="$(mktemp)"
curl "$ETHERPAD_SERVER/p/$PAD_NAME/export/txt" >"$PAD_FILE" curl "$ETHERPAD_SERVER/p/$PAD_NAME/export/txt" >"$PAD_FILE"
# Import the pad into codimd # Import the pad into codimd
OUTPUT="$(./codimd import "$PAD_FILE")" OUTPUT="$(./codimd import "$PAD_FILE")"
echo "$PAD_NAME -> $OUTPUT" >>"$REDIRECTS_FILE" echo "$PAD_NAME -> $OUTPUT" >>"$REDIRECTS_FILE"

View file

@ -0,0 +1,52 @@
Migrations and Notable Changes
===
## Migrating to 1.3.2
This is not a breaking change, but to stay up to date with the community
repository, you may need to update a few urls. This is not a breaking change.
See more at [issue #10](https://github.com/codimd/server/issues/10)
**Native setup using git:**
Change the upstream remote using `git remote set-url origin https://github.com/codimd/server.git`.
**Docker:**
When you use our [container repository](https://github.com/codimd/container)
(which was previously `codimd-container`) all you can simply run `git pull` and
your `docker-compose.yml` will be updated.
When you setup things yourself, make sure you use the new image:
[`quay.io/codimd/server`](https://quay.io/repository/codimd/server?tab=tags).
**Heroku:**
All you need to do is [disconnect GitHub](https://devcenter.heroku.com/articles/github-integration#disconnecting-from-github)
and [reconnect it](https://devcenter.heroku.com/articles/github-integration#enabling-github-integration)
with this new repository.
Or you can use our Heroku button and redeploy your instance and link the old
database again.
## Migrating to 1.1.0
We deprecated the older lower case config style and moved on to camel case style. Please have a look at the current `config.json.example` and check the warnings on startup.
*Notice: This is not a breaking change right now but will be in the future*
## Migrating to 0.5.0
[migration-to-0.5.0 migration tool](https://github.com/hackmdio/migration-to-0.5.0)
We don't use LZString to compress socket.io data and DB data after version 0.5.0.
Please run the migration tool if you're upgrading from the old version.
## Migrating to 0.4.0
[migration-to-0.4.0 migration tool](https://github.com/hackmdio/migration-to-0.4.0)
We've dropped MongoDB after version 0.4.0.
So here is the migration tool for you to transfer the old DB data to the new DB.
This tool is also used for official service.

View file

@ -1,7 +1,7 @@
Minio Guide for CodiMD Minio Guide for CodiMD
=== ===
***Note:** This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!* **Note:** *This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!*
1. First of all you need to setup Minio itself. 1. First of all you need to setup Minio itself.
@ -9,7 +9,7 @@ Minio Guide for CodiMD
production setup. production setup.
For checking it out and development purposes a non-persistent setup is enough: For checking it out and development purposes a non-persistent setup is enough:
```console ```sh
docker run --name test-minio --rm -d -p 9000:9000 minio/minio server /data docker run --name test-minio --rm -d -p 9000:9000 minio/minio server /data
``` ```
@ -18,29 +18,29 @@ Minio Guide for CodiMD
2. Next step is to get the credentials form the container: 2. Next step is to get the credentials form the container:
``` ```sh
docker logs test-minio docker logs test-minio
``` ```
![docker logs](images/minio-image-upload/docker-logs.png) ![docker logs](../images/minio-image-upload/docker-logs.png)
3. Open http://localhost:9000 and login with the shown credentials. 3. Open http://localhost:9000 and login with the shown credentials.
![minio default view](images/minio-image-upload/default-view.png) ![minio default view](../images/minio-image-upload/default-view.png)
4. Create a bucket for HackMD 4. Create a bucket for CodiMD
![minio create bucket](images/minio-image-upload/create-bucket.png) ![minio create bucket](../images/minio-image-upload/create-bucket.png)
5. Add a policy for the prefix `uploads` and make it read-only. 5. Add a policy for the prefix `uploads` and make it read-only.
![minio edit policy](images/minio-image-upload/open-edit-policy.png) ![minio edit policy](../images/minio-image-upload/open-edit-policy.png)
*Open policy editor* *Open policy editor*
![minio policy adding](images/minio-image-upload/create-policy.png) ![minio policy adding](../images/minio-image-upload/create-policy.png)
*Add policy for uploads* *Add policy for uploads*
6. Set credentials and configs for Minio in HackMD's `config.json` 6. Set credentials and configs for Minio in CodiMD's `config.json`
```JSON ```JSON
"minio": { "minio": {
@ -58,7 +58,7 @@ Minio Guide for CodiMD
7. Set bucket name 7. Set bucket name
```JSON ```JSON
"s3bucket": "hackmd" "s3bucket": "codimd"
``` ```
8. Set upload type. 8. Set upload type.
@ -79,7 +79,7 @@ Minio Guide for CodiMD
"port": 9000, "port": 9000,
"secure": false "secure": false
}, },
"s3bucket": "hackmd", "s3bucket": "codimd",
"imageuploadtype": "minio" "imageuploadtype": "minio"
} }
``` ```

View file

@ -1,18 +1,19 @@
# Guide - Setup CodiMD S3 image upload Guide - Setup CodiMD S3 image upload
===
***Note:** This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!* **Note:** *This guide was written before the renaming. Just replace `HackMD` with `CodiMD` in your mind :smile: thanks!*
1. Go to [AWS S3 console](https://console.aws.amazon.com/s3/home) and create a new bucket. 1. Go to [AWS S3 console](https://console.aws.amazon.com/s3/home) and create a new bucket.
![create-bucket](images/s3-image-upload/create-bucket.png) ![create-bucket](../images/s3-image-upload/create-bucket.png)
2. Click on bucket, select **Properties** on the side panel, and find **Permission** section. Click **Edit bucket policy**. 2. Click on bucket, select **Properties** on the side panel, and find **Permission** section. Click **Edit bucket policy**.
![bucket-property](images/s3-image-upload/bucket-property.png) ![bucket-property](../images/s3-image-upload/bucket-property.png)
3. Enter the following policy, replace `bucket_name` with your bucket name: 3. Enter the following policy, replace `bucket_name` with your bucket name:
![bucket-policy-editor](images/s3-image-upload/bucket-policy-editor.png) ![bucket-policy-editor](../images/s3-image-upload/bucket-policy-editor.png)
```json ```json
{ {
@ -32,15 +33,15 @@
5. Enter user page, select **Permission** tab, look at **Inline Policies** section, and click **Create User Policy** 5. Enter user page, select **Permission** tab, look at **Inline Policies** section, and click **Create User Policy**
![iam-user](images/s3-image-upload/iam-user.png) ![iam-user](../images/s3-image-upload/iam-user.png)
6. Select **Custom Policy** 6. Select **Custom Policy**
![custom-policy](images/s3-image-upload/custom-policy.png) ![custom-policy](../images/s3-image-upload/custom-policy.png)
7. Enter the following policy, replace `bucket_name` with your bucket name: 7. Enter the following policy, replace `bucket_name` with your bucket name:
![review-policy](images/s3-image-upload/review-policy.png) ![review-policy](../images/s3-image-upload/review-policy.png)
```json ```json
{ {
@ -76,7 +77,7 @@
} }
``` ```
9. In additional to edit `config.json` directly, you could also try [environment variable](https://github.com/hackmdio/hackmd#environment-variables-will-overwrite-other-server-configs). 9. In additional to edit `config.json` directly, you could also try [environment variables](../configuration-env-vars.md).
## Related Tools ## Related Tools

40
docs/history.md Normal file
View file

@ -0,0 +1,40 @@
History of CodiMD
===
## It started with HackMD
HackMD is the origin of this project, which was mostly developed by Max Wu and
Yukai Huang. Originally, this was open source under MIT license, but was
[relicensed in October 2017 to be AGPLv3](https://github.com/hackmdio/codimd/pull/578).
At the same time, [hackmd.io](https://hackmd.io) was founded to offer a
commercial version of HackMD.
The AGPLv3-version was developed and released by the community, this was for a
while referred to as "HackMD community edition".
*For more on the splitting of the projects, please refer to [A note to our community (2017-10-11)](https://hackmd.io/c/community-news/https%3A%2F%2Fhackmd.io%2Fs%2Fr1_4j9_hZ).*
## HackMD CE became CodiMD
In June 2018, CodiMD was renamed from its former name "HackMD" and continued to
be developed under AGPLv3 by the community. We decided to change the name to
break the confusion between HackMD (enterprise offering) and CodiMD (community
project), as people mistook it for an open core development model.
*For the whole renaming story, see the [issue where the renaming was discussed](https://github.com/hackmdio/hackmd/issues/720).*
## CodiMD went independent
In March 2019, a discussion over licensing, governance and the future of CodiMD
lead to the formation of a distinct GitHub organization. Up to that point, the
community project resided in the organization of hackmdio but was for the most
part self-organized.
During that debate, we did not reach an agreement that would have allowed us to
move the repository, so we simply forked it. We still welcome the HackMD team
as part of our community, especially since a large portion of this code base
originated with them.
*For the debate that lead to this step, please refer to the [governance debate](https://github.com/hackmdio/hackmd/issues/1170) and [the announcement of the new repository](https://github.com/codimd/server/issues/10).*

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View file

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View file

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

View file

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View file

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View file

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View file

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View file

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View file

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View file

Before

Width:  |  Height:  |  Size: 234 KiB

After

Width:  |  Height:  |  Size: 234 KiB

View file

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View file

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 180 KiB

View file

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View file

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 198 KiB

View file

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 187 KiB

View file

Before

Width:  |  Height:  |  Size: 159 KiB

After

Width:  |  Height:  |  Size: 159 KiB

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View file

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View file

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View file

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View file

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

View file

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

6
docs/setup/cloudron.md Normal file
View file

@ -0,0 +1,6 @@
Cloudron
===
Install CodiMD on [Cloudron](https://cloudron.io):
[![Install](https://cloudron.io/img/button.svg)](https://cloudron.io/button.html?app=io.hackmd.cloudronapp)

23
docs/setup/docker.md Normal file
View file

@ -0,0 +1,23 @@
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/codimd/container/raw/master/docker-compose.yml&stack_name=codimd)
**Debian-based version:**
[![Docker Repository on Quay](https://quay.io/repository/codimd/server/status "Docker Repository on Quay")](https://quay.io/repository/codimd/server)
**Alpine-based version:**
[![Docker Repository on Quay](https://quay.io/repository/codimd/server/status "Docker Repository on Quay")](https://quay.io/repository/codimd/server)
The easiest way to setup CodiMD using docker are using the following three commands:
```sh
git clone https://github.com/codimd/container.git
cd codimd-container
docker-compose up
```
Read more about it in the [container repository](https://github.com/codimd/container).

7
docs/setup/heroku.md Normal file
View file

@ -0,0 +1,7 @@
Heroku Deployment
===
You can quickly setup a sample Heroku CodiMD application by clicking the button
below.
[![Deploy on Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/codimd/server/tree/master)

6
docs/setup/kubernetes.md Normal file
View file

@ -0,0 +1,6 @@
Kubernetes
===
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).

View file

@ -0,0 +1,39 @@
Manual Installation
===
## Requirements on your server
- Node.js 6.x or up (test up to 7.5.0) and <10.x
- Database (PostgreSQL, MySQL, MariaDB, SQLite, MSSQL) use charset `utf8`
- npm (and its dependencies, [node-gyp](https://github.com/nodejs/node-gyp#installation))
- `libssl-dev` for building scrypt (see [here](https://github.com/ml1nk/node-scrypt/blob/master/README.md#installation-instructions) for further information)
- For **building** CodiMD we recommend to use a machine with at least **2GB** RAM
## Instructions
1. Download a release and unzip or clone into a directory
2. Enter the directory and type `bin/setup`, which will install npm dependencies and create configs. The setup script is written in Bash, you would need bash as a prerequisite.
3. Setup the configs, see more below
4. Setup environment variables which will overwrite the configs
5. Build front-end bundle by `npm run build` (use `npm run dev` if you are in development)
6. Modify the file named `.sequelizerc`, change the value of the variable `url` with your db connection string
For example: `postgres://username:password@localhost:5432/codimd`
7. Run `node_modules/.bin/sequelize db:migrate`, this step will migrate your db to the latest schema
8. Run the server as you like (node, forever, pm2)
## How to upgrade your installation
:warning: When you are still running from the old repository, please run: `git remote set-url origin https://github.com/codimd/server.git` :warning:
If you are upgrading CodiMD from an older version, follow these steps:
1. Fully stop your old server first (important)
2. `git pull` or do whatever that updates the files
3. `npm install` to update dependencies
4. Build front-end bundle by `npm run build` (use `npm run dev` if you are in development)
5. Modify the file named `.sequelizerc`, change the value of the variable `url` with your db connection string
For example: `postgres://username:password@localhost:5432/codimd`
6. Run `node_modules/.bin/sequelize db:migrate`, this step will migrate your db to the latest schema
7. Start your whole new server!

161
docs/slide-options.md Normal file
View file

@ -0,0 +1,161 @@
Slide Separators
===
If you're getting started with reveal.js slides, there are a few things you need to know.
There are two types of slides, those that transition horizontally and those that transition vertically (subslides).
The following separators are used for each in the CodiMD syntax:
```
# First Slide
---
# Next slide
----
## Subslide
```
as you can see, horizontal transitions are separated by `---` and vertical transitions by `----`
## Basic YAML header
It's possible to customise the slide options using the YAML header in the slide markdown.
eg:
```
---
title: Example Slide
tags: presentation
slideOptions:
theme: solarized
transition: 'fade'
# parallaxBackgroundImage: 'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'
---
```
make sure to have two spaces only at the start of the listed slide options.
you can comment out options with a `#`
### Some other options
```
# Display controls in the bottom right corner
controls: true
# Display a presentation progress bar
progress: true
# Set default timing of 2 minutes per slide
defaultTiming: 120
# Display the page number of the current slide
slideNumber: false
# Push each slide change to the browser history
history: false
# Enable keyboard shortcuts for navigation
keyboard: true
# Enable the slide overview mode
overview: true
# Vertical centering of slides
center: true
# Enables touch navigation on devices with touch input
touch: true
# Loop the presentation
loop: false
# Change the presentation direction to be RTL
rtl: false
# Randomizes the order of slides each time the presentation loads
shuffle: false
# Turns fragments on and off globally
fragments: true
# Flags if the presentation is running in an embedded mode,
# i.e. contained within a limited portion of the screen
embedded: false
# Flags if we should show a help overlay when the questionmark
# key is pressed
help: true
# Flags if speaker notes should be visible to all viewers
showNotes: false
# Global override for autolaying embedded media (video/audio/iframe)
# - null: Media will only autoplay if data-autoplay is present
# - true: All media will autoplay, regardless of individual setting
# - false: No media will autoplay, regardless of individual setting
autoPlayMedia: null
# Number of milliseconds between automatically proceeding to the
# next slide, disabled when set to 0, this value can be overwritten
# by using a data-autoslide attribute on your slides
autoSlide: 0
# Stop auto-sliding after user input
autoSlideStoppable: true
# Use this method for navigation when auto-sliding
autoSlideMethod: Reveal.navigateNext
# Enable slide navigation via mouse wheel
mouseWheel: false
# Hides the address bar on mobile devices
hideAddressBar: true
# Opens links in an iframe preview overlay
previewLinks: false
# Transition style
transition: 'slide'
# none/fade/slide/convex/concave/zoom
# Transition speed
transitionSpeed: 'default'
# default/fast/slow
# Transition style for full page slide backgrounds
backgroundTransition: 'fade'
# none/fade/slide/convex/concave/zoom
# Number of slides away from the current that are visible
viewDistance: 3
# Parallax background image
parallaxBackgroundImage: ''
# e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"
# Parallax background size
parallaxBackgroundSize: ''
# CSS syntax, e.g. "2100px 900px"
# Number of pixels to move the parallax background per slide
# - Calculated automatically unless specified
# - Set to 0 to disable movement along an axis
parallaxBackgroundHorizontal: null
parallaxBackgroundVertical: null
# The display mode that will be used to show slides
display: 'block'
```
## Customising individual slides
custom background image:
```
---
<!-- .slide: data-background="https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg" -->
#### testslide
---
```

View file

@ -58,8 +58,11 @@ module.exports = {
heartbeatTimeout: 10000, heartbeatTimeout: 10000,
// 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
}, },
@ -138,6 +141,7 @@ module.exports = {
idpCert: undefined, idpCert: undefined,
issuer: undefined, issuer: undefined,
identifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', identifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
disableRequestedAuthnContext: false,
groupAttribute: undefined, groupAttribute: undefined,
externalGroups: [], externalGroups: [],
requiredGroups: [], requiredGroups: [],

View file

@ -49,6 +49,9 @@ module.exports = {
secure: toBooleanConfig(process.env.CMD_MINIO_SECURE), secure: toBooleanConfig(process.env.CMD_MINIO_SECURE),
port: toIntegerConfig(process.env.CMD_MINIO_PORT) port: toIntegerConfig(process.env.CMD_MINIO_PORT)
}, },
lutim: {
url: process.env.CMD_LUTIM_URL
},
s3bucket: process.env.CMD_S3_BUCKET, s3bucket: process.env.CMD_S3_BUCKET,
azure: { azure: {
connectionString: process.env.CMD_AZURE_CONNECTION_STRING, connectionString: process.env.CMD_AZURE_CONNECTION_STRING,
@ -115,6 +118,7 @@ module.exports = {
idpCert: process.env.CMD_SAML_IDPCERT, idpCert: process.env.CMD_SAML_IDPCERT,
issuer: process.env.CMD_SAML_ISSUER, issuer: process.env.CMD_SAML_ISSUER,
identifierFormat: process.env.CMD_SAML_IDENTIFIERFORMAT, identifierFormat: process.env.CMD_SAML_IDENTIFIERFORMAT,
disableRequestedAuthnContext: toBooleanConfig(process.env.CMD_SAML_DISABLEREQUESTEDAUTHNCONTEXT),
groupAttribute: process.env.CMD_SAML_GROUPATTRIBUTE, groupAttribute: process.env.CMD_SAML_GROUPATTRIBUTE,
externalGroups: toArrayConfig(process.env.CMD_SAML_EXTERNALGROUPS, '|', []), externalGroups: toArrayConfig(process.env.CMD_SAML_EXTERNALGROUPS, '|', []),
requiredGroups: toArrayConfig(process.env.CMD_SAML_REQUIREDGROUPS, '|', []), requiredGroups: toArrayConfig(process.env.CMD_SAML_REQUIREDGROUPS, '|', []),

View file

@ -109,6 +109,7 @@ module.exports = {
idpCert: process.env.HMD_SAML_IDPCERT, idpCert: process.env.HMD_SAML_IDPCERT,
issuer: process.env.HMD_SAML_ISSUER, issuer: process.env.HMD_SAML_ISSUER,
identifierFormat: process.env.HMD_SAML_IDENTIFIERFORMAT, identifierFormat: process.env.HMD_SAML_IDENTIFIERFORMAT,
disableRequestedAuthnContext: toBooleanConfig(process.env.HMD_SAML_DISABLEREQUESTEDAUTHNCONTEXT),
groupAttribute: process.env.HMD_SAML_GROUPATTRIBUTE, groupAttribute: process.env.HMD_SAML_GROUPATTRIBUTE,
externalGroups: toArrayConfig(process.env.HMD_SAML_EXTERNALGROUPS, '|', []), externalGroups: toArrayConfig(process.env.HMD_SAML_EXTERNALGROUPS, '|', []),
requiredGroups: toArrayConfig(process.env.HMD_SAML_REQUIREDGROUPS, '|', []), requiredGroups: toArrayConfig(process.env.HMD_SAML_REQUIREDGROUPS, '|', []),

View file

@ -152,7 +152,7 @@ for (let i = keys.length; i--;) {
// Notify users about the prefix change and inform them they use legacy prefix for environment variables // Notify users about the prefix change and inform them they use legacy prefix for environment variables
if (Object.keys(process.env).toString().indexOf('HMD_') !== -1) { if (Object.keys(process.env).toString().indexOf('HMD_') !== -1) {
logger.warn('Using legacy HMD prefix for environment variables. Please change your variables in future. For details see: https://github.com/hackmdio/codimd#environment-variables-will-overwrite-other-server-configs') logger.warn('Using legacy HMD prefix for environment variables. Please change your variables in future. For details see: https://github.com/codimd/server#environment-variables-will-overwrite-other-server-configs')
} }
// Generate session secret if it stays on default values // Generate session secret if it stays on default values
@ -164,8 +164,8 @@ if (config.sessionSecret === 'secret') {
} }
// Validate upload upload providers // Validate upload upload providers
if (['filesystem', 's3', 'minio', 'imgur', 'azure'].indexOf(config.imageUploadType) === -1) { if (['filesystem', 's3', 'minio', 'imgur', 'azure', 'lutim'].indexOf(config.imageUploadType) === -1) {
logger.error('"imageuploadtype" is not correctly set. Please use "filesystem", "s3", "minio", "azure" or "imgur". Defaulting to "filesystem"') logger.error('"imageuploadtype" is not correctly set. Please use "filesystem", "s3", "minio", "azure", "lutim" or "imgur". Defaulting to "filesystem"')
config.imageUploadType = 'filesystem' config.imageUploadType = 'filesystem'
} }

View file

@ -37,7 +37,7 @@ exports.generateAvatarURL = function (name, email = '', big = true) {
let hexDigest = hash.digest('hex') let hexDigest = hash.digest('hex')
if (email !== '' && config.allowGravatar) { if (email !== '' && config.allowGravatar) {
photo = 'https://www.gravatar.com/avatar/' + hexDigest; photo = 'https://cdn.libravatar.org/avatar/' + hexDigest;
if (big) { if (big) {
photo += '?s=400' photo += '?s=400'
} else { } else {

View file

@ -427,7 +427,7 @@ function publishNoteActions (req, res, next) {
actionDownload(req, res, note) actionDownload(req, res, note)
break break
case 'edit': case 'edit':
res.redirect(config.serverURL + '/' + (note.alias ? note.alias : models.Note.encodeNoteId(note.id))) res.redirect(config.serverURL + '/' + (note.alias ? note.alias : models.Note.encodeNoteId(note.id)) + '?both')
break break
default: default:
res.redirect(config.serverURL + '/s/' + note.shortid) res.redirect(config.serverURL + '/s/' + note.shortid)
@ -441,7 +441,7 @@ function publishSlideActions (req, res, next) {
var action = req.params.action var action = req.params.action
switch (action) { switch (action) {
case 'edit': case 'edit':
res.redirect(config.serverURL + '/' + (note.alias ? note.alias : models.Note.encodeNoteId(note.id))) res.redirect(config.serverURL + '/' + (note.alias ? note.alias : models.Note.encodeNoteId(note.id)) + '?both')
break break
default: default:
res.redirect(config.serverURL + '/p/' + note.shortid) res.redirect(config.serverURL + '/p/' + note.shortid)

View file

@ -17,7 +17,8 @@ passport.use(new SamlStrategy({
entryPoint: config.saml.idpSsoUrl, entryPoint: config.saml.idpSsoUrl,
issuer: config.saml.issuer || config.serverURL, issuer: config.saml.issuer || config.serverURL,
cert: fs.readFileSync(config.saml.idpCert, 'utf-8'), cert: fs.readFileSync(config.saml.idpCert, 'utf-8'),
identifierFormat: config.saml.identifierFormat identifierFormat: config.saml.identifierFormat,
disableRequestedAuthnContext: config.saml.disableRequestedAuthnContext
}, function (user, done) { }, function (user, done) {
// check authorization if needed // check authorization if needed
if (config.saml.externalGroups && config.saml.groupAttribute) { if (config.saml.externalGroups && config.saml.groupAttribute) {

View file

@ -0,0 +1,31 @@
'use strict'
const config = require('../../config')
const logger = require('../../logger')
const lutim = require('lutim')
exports.uploadImage = function (imagePath, callback) {
if (!imagePath || typeof imagePath !== 'string') {
callback(new Error('Image path is missing or wrong'), null)
return
}
if (!callback || typeof callback !== 'function') {
logger.error('Callback has to be a function')
return
}
if (config.lutim && config.lutim.url) {
lutim.setAPIUrl(config.lutim.url)
}
lutim.uploadImage(imagePath)
.then(function (json) {
if (config.debug) {
logger.info('SERVER uploadimage success: ' + JSON.stringify(json))
}
callback(null, lutim.getAPIUrl() + json.msg.short)
}).catch(function (err) {
callback(new Error(err), null)
})
}

View file

@ -40,7 +40,9 @@ exports.uploadImage = function (imagePath, callback) {
callback(new Error(err), null) callback(new Error(err), null)
return return
} }
callback(null, `${protocol}://${config.minio.endPoint}:${config.minio.port}/${config.s3bucket}/${key}`) let hidePort = [80, 443].includes(config.minio.port)
let urlPort = hidePort ? '' : `:${config.minio.port}`
callback(null, `${protocol}://${config.minio.endPoint}${urlPort}/${config.s3bucket}/${key}`)
}) })
}) })
} }

View file

@ -29,8 +29,8 @@
"Import from browser": "Importuj z przeglądarki", "Import from browser": "Importuj z przeglądarki",
"Releases": "Wydania", "Releases": "Wydania",
"Are you sure?": "Jesteś pewny?", "Are you sure?": "Jesteś pewny?",
"Do you really want to delete this note?": "Do you really want to delete this note?", "Do you really want to delete this note?": "Czy chcesz usunąć tą notatkę?",
"All users will lose their connection.": "All users will lose their connection.", "All users will lose their connection.": "Wszyscy użytkownicy stracą swoje połączenie.",
"Cancel": "Anuluj", "Cancel": "Anuluj",
"Yes, do it!": "Tak, zrób to!", "Yes, do it!": "Tak, zrób to!",
"Choose method": "Wybierz metodę", "Choose method": "Wybierz metodę",
@ -62,7 +62,7 @@
"Refresh": "Odśwież", "Refresh": "Odśwież",
"Contacts": "Kontakty", "Contacts": "Kontakty",
"Report an issue": "Zgłoś błąd", "Report an issue": "Zgłoś błąd",
"Meet us on %s": "Meet us on %s", "Meet us on %s": "Spotkaj się z nami na %s",
"Send us email": "Wyślij nam email", "Send us email": "Wyślij nam email",
"Documents": "Dokumenty", "Documents": "Dokumenty",
"Features": "Funkcje", "Features": "Funkcje",
@ -104,12 +104,16 @@
"OR": "LUB", "OR": "LUB",
"Export to Snippet": "Eksportuj do Snippet", "Export to Snippet": "Eksportuj do Snippet",
"Select Visibility Level": "Wybierz poziom widoczności", "Select Visibility Level": "Wybierz poziom widoczności",
"Night Theme": "Night Theme", "Night Theme": "Motyw Nocny",
"Follow us on %s and %s.": "Follow us on %s, and %s.", "Follow us on %s and %s.": "Znajdź nas na %s oraz %s.",
"Privacy": "Privacy", "Privacy": "Prywatność",
"Terms of Use": "Terms of Use", "Terms of Use": "Warunki korzystania",
"Do you really want to delete your user account?": "Do you really want to delete your user account?", "Do you really want to delete your user account?": "Czy chcesz usunąć swoje konto użytkownika?",
"This will delete your account, all notes that are owned by you and remove all references to your account from other notes.": "This will delete your account, all notes that are owned by you and remove all references to your account from other notes.", "This will delete your account, all notes that are owned by you and remove all references to your account from other notes.": "Ta akcja usunie twoje konto, wszystkie notatki które posiadasz oraz wszystkie referencje do tego konta w twoich pozostałych notatkach.",
"Delete user": "Delete user", "Delete user": "Usuń użytkownika",
"Export user data": "Export user data" "Export user data": "Eksportuj dane użytkownika",
"Help us translating on %s": "Pomóż nam przetłumaczyć na język %s",
"Source Code": "Kod źródłowy",
"Register": "Zarejestruj",
"Powered by %s": "Wspierany przez %s"
} }

View file

@ -34,7 +34,7 @@
"Cancel": "Одустани", "Cancel": "Одустани",
"Yes, do it!": "Да, уради!", "Yes, do it!": "Да, уради!",
"Choose method": "Изаберите начин", "Choose method": "Изаберите начин",
"Sign in via %s": "Пријавите се помоћу %s", "Sign in via %s": "Пријави се уз %s",
"New": "Ново", "New": "Ново",
"Publish": "Објави", "Publish": "Објави",
"Extra": "Додатно", "Extra": "Додатно",
@ -113,5 +113,7 @@
"Delete user": "Брисање корисника", "Delete user": "Брисање корисника",
"Export user data": "Извоз свих корисничких података", "Export user data": "Извоз свих корисничких података",
"Help us translating on %s": "Помозите нам да преведемо на %s", "Help us translating on %s": "Помозите нам да преведемо на %s",
"Source Code": "Изворни код" "Source Code": "Изворни код",
"Register": "Региструј се",
"Powered by %s": "Покреће %s"
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "CodiMD", "name": "CodiMD",
"version": "1.3.1", "version": "1.3.2",
"description": "Realtime collaborative markdown notes on all platforms.", "description": "Realtime collaborative markdown notes on all platforms.",
"main": "app.js", "main": "app.js",
"license": "AGPL-3.0", "license": "AGPL-3.0",
@ -10,10 +10,9 @@
"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", "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": "echo 'standard is no longer being used, use `npm run eslint` instead!' && exit 1", "standard": "echo 'standard is no longer being used, use `npm run eslint` instead!' && exit 1",
"dev": "webpack --config webpack.dev.js --progress --colors --watch", "dev": "webpack --config webpack.dev.js --progress --colors --watch",
"heroku-prebuild": "bin/heroku",
"build": "webpack --config webpack.prod.js --progress --colors --bail", "build": "webpack --config webpack.prod.js --progress --colors --bail",
"postinstall": "bin/heroku", "start": "sequelize db:migrate && node app.js"
"start": "sequelize db:migrate && node app.js",
"doctoc": "doctoc --title='# Table of Contents' README.md"
}, },
"dependencies": { "dependencies": {
"@hackmd/js-sequence-diagrams": "^0.0.1-alpha.2", "@hackmd/js-sequence-diagrams": "^0.0.1-alpha.2",
@ -57,12 +56,14 @@
"jquery-mousewheel": "^3.1.13", "jquery-mousewheel": "^3.1.13",
"jquery-ui": "^1.12.1", "jquery-ui": "^1.12.1",
"js-cookie": "^2.1.3", "js-cookie": "^2.1.3",
"js-sequence-diagrams": "git+https://github.com/codimd/js-sequence-diagrams.git",
"js-url": "^2.3.0", "js-url": "^2.3.0",
"js-yaml": "^3.7.0", "js-yaml": "^3.13.1",
"jsdom-nogyp": "^0.8.3", "jsdom-nogyp": "^0.8.3",
"keymaster": "^1.6.2", "keymaster": "^1.6.2",
"list.js": "^1.5.0", "list.js": "^1.5.0",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"lutim": "^1.0.2",
"lz-string": "git+https://github.com/hackmdio/lz-string.git", "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",
@ -140,7 +141,7 @@
"engines": { "engines": {
"node": ">=6.x" "node": ">=6.x"
}, },
"bugs": "https://github.com/hackmdio/codimd/issues", "bugs": "https://github.com/codimd/server/issues",
"keywords": [ "keywords": [
"Collaborative", "Collaborative",
"Markdown", "Markdown",
@ -149,17 +150,18 @@
"homepage": "https://codimd.org", "homepage": "https://codimd.org",
"maintainers": [ "maintainers": [
{ {
"name": "Max Wu", "name": "Claudius Coenen",
"email": "jackymaxj@gmail.com" "url": "https://www.claudiuscoenen.de/"
}, },
{ {
"name": "Christoph (Sheogorath) Kern", "name": "Christoph (Sheogorath) Kern",
"email": "codimd@sheogorath.shivering-isles.com" "email": "codimd@sheogorath.shivering-isles.com",
"url": "https://shivering-isles.com"
} }
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/hackmdio/codimd.git" "url": "https://github.com/codimd/server.git"
}, },
"devDependencies": { "devDependencies": {
"babel-cli": "^6.26.0", "babel-cli": "^6.26.0",
@ -171,7 +173,6 @@
"babel-runtime": "^6.26.0", "babel-runtime": "^6.26.0",
"copy-webpack-plugin": "^4.5.2", "copy-webpack-plugin": "^4.5.2",
"css-loader": "^1.0.0", "css-loader": "^1.0.0",
"doctoc": "^1.4.0",
"ejs-loader": "^0.3.1", "ejs-loader": "^0.3.1",
"eslint": "^5.9.0", "eslint": "^5.9.0",
"eslint-config-standard": "^12.0.0", "eslint-config-standard": "^12.0.0",

View file

@ -385,7 +385,7 @@ div[contenteditable]:empty:not(:focus):before{
color: #eee; color: #eee;
} }
.night .btn.btn-default.ui-view.active{ .night .btn.btn-default.active{
background: #202020; background: #202020;
} }

View file

@ -1,131 +1,138 @@
Features # Features
===
## Introduction
Introduction
===
<i class="fa fa-file-text"></i> **CodiMD** is a real-time, multi-platform collaborative markdown note editor. <i class="fa fa-file-text"></i> **CodiMD** is a real-time, multi-platform collaborative markdown note editor.
This means that you can write notes with other people on your **desktop**, **tablet** or even on the **phone**. This means that you can write notes with other people on your **desktop**, **tablet** or even on the **phone**.
You can sign-in via multiple auth providers like **Facebook**, **Twitter**, **GitHub** and many more on the [_homepage_](/). You can sign-in via multiple auth providers like **Facebook**, **Twitter**, **GitHub** and many more on the [_homepage_](/).
If you experience any _issues_, feel free to report it on [**GitHub**](https://github.com/hackmdio/codimd/issues). If you experience any _issues_, feel free to report it on [**GitHub**](https://github.com/codimd/server/issues).
Or meet us on [**Matrix.org**](https://riot.im/app/#/room/#codimd:matrix.org) for dev-talk and interactive help. Or meet us on [**Matrix.org**](https://riot.im/app/#/room/#codimd:matrix.org) for dev-talk and interactive help.
**Thank you very much!** **Thank you very much!**
Workspace ## Workspace
===
## Modes ### Modes
**Desktop & Tablet**
#### Desktop & Tablet
<i class="fa fa-edit fa-fw"></i> Edit: See only the editor.
<i class="fa fa-eye fa-fw"></i> View: See only the result. <i class="fa fa-eye fa-fw"></i> View: See only the result.
<i class="fa fa-columns fa-fw"></i> Both: See both in split view. <i class="fa fa-columns fa-fw"></i> Both: See editor and result at the same time.
<i class="fa fa-pencil fa-fw"></i> Edit: See only the editor.
**Mobile** #### Mobile
<i class="fa fa-toggle-on fa-fw"></i> View: See only the result. <i class="fa fa-eye fa-fw"></i> View: See only the result.
<i class="fa fa-toggle-off fa-fw"></i> Edit: See only the editor. <i class="fa fa-pencil fa-fw"></i> Edit: See only the editor.
### Night Mode
## Night Mode:
When you are tired of a white screen and like a night mode, click on the little moon <i class="fa fa-moon-o"></i> and turn on the night view of CodiMD. When you are tired of a white screen and like a night mode, click on the little moon <i class="fa fa-moon-o"></i> and turn on the night view of CodiMD.
The editor view, which is in night mode by default, can also be toggled between night and day view using the the little sun<i class="fa fa-sun-o fa-fw"></i>. The editor view, which is in night mode by default, can also be toggled between night and day view using the the little sun<i class="fa fa-sun-o fa-fw"></i>.
## Image Upload: ### Image Upload
You can upload an image simply by clicking on the camera button <i class="fa fa-camera"></i>.
You can upload an image simply by clicking on the upload button <i class="fa fa-upload"></i>.
Alternatively, you can **drag-n-drop** an image into the editor. Even **pasting** images is possible! Alternatively, you can **drag-n-drop** an image into the editor. Even **pasting** images is possible!
This will automatically upload the image to **[imgur](http://imgur.com)**, **[Amazon S3](https://aws.amazon.com/s3/)**, **[Minio](https://minio.io)** or **local filesystem**, nothing to worry about. :tada: This will automatically upload the image to **[imgur](http://imgur.com)**, **[Amazon S3](https://aws.amazon.com/s3/)**, **[Minio](https://minio.io)** or the **local filesystem** (depending on the instance's configuration), nothing to worry about. :tada:
![imgur](https://i.imgur.com/9cgQVqD.png) ![imgur](https://i.imgur.com/9cgQVqD.png)
## Share Notes: ### Share Notes
If you want to share an **editable** note, just copy the URL. If you want to share an **editable** note, just copy the URL.
If you want to share a **read-only** note, simply press publish button <i class="fa fa-share-square-o"></i> and copy the URL. If you want to share a **read-only** note, simply press the publish button <i class="fa fa-share-square-o"></i> and copy the URL.
## Save a Note: ### Save a Note
Currently, you can save to **Dropbox** <i class="fa fa-dropbox"></i> or save an `.md` file <i class="fa fa-file-text"></i> locally.
## Import Notes: Currently, you can save to **Dropbox** <i class="fa fa-dropbox"></i> (depending on the instance's configuration) or save a Markdown <i class="fa fa-file-text"></i>, HTML or raw HTML <i class="fa fa-file-code-o"></i> file locally.
Similarly to the _save_ feature, you can also import an `.md` file from **Dropbox** <i class="fa fa-dropbox"></i>,
or import content from your **clipboard** <i class="fa fa-clipboard"></i>, and that can parse some **html** which might be useful :smiley:
## Permissions: ### Import Notes
It is possible to change the access permission to a note through the little button on the top right of the view.
Similarly to the _save_ feature, you can also import a Markdown file from **Dropbox** <i class="fa fa-dropbox"></i> (depending on the instance's configuration), or import content from your **clipboard** <i class="fa fa-clipboard"></i>, which can parse some HTML. :smiley:
### Permissions
It is possible to change the access permission of a note through the little button on the top right of the view.
There are four possible options: There are four possible options:
| |Owner read/write|Signed-in read|Signed-in write|Guest read|Guest write| | |Owner read/write|Signed-in read|Signed-in write|Guest read|Guest write|
|:-----------------------------|:--------------:|:------------:|:-------------:|:--------:|:---------:| |:-----------------------------|:--------------:|:------------:|:-------------:|:--------:|:---------:|
|<span class="text-nowrap"><i class="fa fa-leaf fa-fw"></i> **Freely**</span> |✔|✔|✔|✔|✔| |<span class="text-nowrap"><i class="fa fa-leaf fa-fw"></i> **Freely**</span>|✔|✔|✔|✔|✔|
|<span class="text-nowrap"><i class="fa fa-pencil fa-fw"></i> **Editable**</span> |✔|✔|✔|✔|✖| |<span class="text-nowrap"><i class="fa fa-pencil fa-fw"></i> **Editable**</span>|✔|✔|✔|✔|✖|
|<span class="text-nowrap"><i class="fa fa-id-card fa-fw"></i> **Limited**</span> |✔|✔|✔|✖|✖| |<span class="text-nowrap"><i class="fa fa-id-card fa-fw"></i> **Limited**</span>|✔|✔|✔|✖|✖|
|<span class="text-nowrap"><i class="fa fa-lock fa-fw"></i> **Locked**</span> |✔|✔|✖|✔|✖| |<span class="text-nowrap"><i class="fa fa-lock fa-fw"></i> **Locked**</span>|✔|✔|✖|✔|✖|
|<span class="text-nowrap"><i class="fa fa-umbrella fa-fw"></i> **Protected**</span> |✔|✔|✖|✖|✖| |<span class="text-nowrap"><i class="fa fa-umbrella fa-fw"></i> **Protected**</span>|✔|✔|✖|✖|✖|
|<span class="text-nowrap"><i class="fa fa-hand-stop-o fa-fw"></i> **Private**</span> |✔|✖|✖|✖|✖| |<span class="text-nowrap"><i class="fa fa-hand-stop-o fa-fw"></i> **Private**</span>|✔|✖|✖|✖|✖|
**Only the owner of the note can change the note's permissions.** **Only the owner of the note can change the note's permissions.**
## Embed a Note: ### Embed a Note
Notes can be embedded as follows: Notes can be embedded as follows:
```xml ```xml
<iframe width="100%" height="500" src="https://hackmd.io/features" frameborder="0"></iframe> <iframe width="100%" height="500" src="https://demo.codimd.io/features" frameborder="0"></iframe>
``` ```
## [Slide Mode](./slide-example): ### [Slide Mode](./slide-example)
You can use a special syntax to organize your note into slides. You can use a special syntax to organize your note into slides.
After that, you can use the **[Slide Mode](./slide-example)** <i class="fa fa-tv"></i> to make a presentation. After that, you can use the **[Slide Mode](./slide-example)** <i class="fa fa-tv"></i> to make a presentation.
Visit the above link for details. Visit the above link for details.
To switch the editor into slide mode, set the [document type](./yaml-metadata#type) to `slide`. To switch the editor into slide mode, set the [document type](./yaml-metadata#type) to `slide`.
View ## View
===
## Table of Contents: ### Autogenerated Table of Contents
You can look at the bottom right section of the view area, there is a _ToC_ button <i class="fa fa-bars"></i>. You can look at the bottom right section of the view area, there is a _ToC_ button <i class="fa fa-bars"></i>.
Pressing that button will show you a current _Table of Contents_, and will highlight which section you're at. Pressing that button will show you a current _Table of Contents_, and will highlight which section you're at.
ToCs support up to **three header levels**. ToCs support up to **three header levels**.
## Permalink ### Permalink
Every header will automatically add a permalink on the right side. Every header will automatically add a permalink on the right side.
You can hover and click <i class="fa fa-chain"></i> to anchor on it. You can hover and click <i class="fa fa-chain"></i> to anchor on it.
Edit: ## Edit
===
## Editor Modes:
You can look in the bottom right section of the editor area, there you'll find a button with `sublime` on it.
When you click it, you can select 3 editor modes:
- sublime (default) ### Editor Modes
- emacs
- vim
## Shortcut Keys: You can look in the bottom right section of the editor area, there you'll find a button with `SUBLIME` on it.
The shortcut keys depend on your selected editor mode. By default they are just like Sublime text, which is pretty quick and convenient. When you click it, you can select 3 editor modes, which will also define your shortcut keys:
> For more information, see [here](https://codemirror.net/demo/sublime.html).
For emacs: - [Sublime](https://codemirror.net/demo/sublime.html) (default)
> For more information, see [here](https://codemirror.net/demo/emacs.html). - [Emacs](https://codemirror.net/demo/emacs.html)
- [Vim](https://codemirror.net/demo/vim.html)
For vim: ### Auto-Complete
> For more information, see [here](https://codemirror.net/demo/vim.html).
## Auto-Complete:
This editor provides full auto-complete hints in markdown. This editor provides full auto-complete hints in markdown.
- Emojis: type `:` to show hints. - Emojis: type `:` to show hints.
- Code blocks: type ` ``` ` and plus a character to show hint. <i hidden>```</i> - Code blocks: type ` ``` `, followed by another character to show syntax highlighting suggestions.
- Headers: type `#` to show hint. - Headers: type `#` to show hint.
- Referrals: type `[]` to show hint. - Referrals: type `[]` to show hint.
- Externals: type `{}` to show hint. - Externals: type `{}` to show hint.
- Images: type `!` to show hint. - Images: type `!` to show hint.
## Title: ### Title
This will take the first **level 1 header** as the note title.
The first **level 1 heading** (e.g. `# Title`) will be used as the note title.
### Tags
## Tags:
Using tags as follows, the specified tags will show in your **history**. Using tags as follows, the specified tags will show in your **history**.
###### tags: `features` `cool` `updated` ###### tags: `features` `cool` `updated`
## [YAML Metadata](./yaml-metadata) ### [YAML Metadata](./yaml-metadata)
You can provide advanced note information to set the browser behavior (visit above link for details): You can provide advanced note information to set the browser behavior (visit above link for details):
- robots: set web robots meta - robots: set web robots meta
- lang: set browser language - lang: set browser language
- dir: set text direction - dir: set text direction
@ -134,23 +141,30 @@ You can provide advanced note information to set the browser behavior (visit abo
- disqus: set to use Disqus - disqus: set to use Disqus
- slideOptions: setup slide mode options - slideOptions: setup slide mode options
## ToC: ### Table of Contents
Use the syntax `[TOC]` to embed table of content into your note.
Use the syntax `[TOC]` to embed a table of contents into your note.
[TOC] [TOC]
## Emoji ### Emoji
You can type any emoji like this :smile: :smiley: :cry: :wink: You can type any emoji like this :smile: :smiley: :cry: :wink:
> See full emoji list [here](http://www.emoji-cheat-sheet.com/). > See full emoji list [here](http://www.emoji-cheat-sheet.com/).
## ToDo List: ### ToDo List
- [ ] ToDos - [ ] ToDos
- [x] Buy some salad - [x] Buy some salad
- [ ] Brush teeth - [ ] Brush teeth
- [x] Drink some water - [x] Drink some water
- [ ] **Click my box** and see the source code, if you're allowed to edit!
### Code Block
## Code Block:
We support many programming languages, use the auto complete function to see the entire list. We support many programming languages, use the auto complete function to see the entire list.
```javascript= ```javascript=
var s = "JavaScript syntax highlighting"; var s = "JavaScript syntax highlighting";
alert(s); alert(s);
@ -168,9 +182,11 @@ function $initHighlight(block, cls) {
} }
} }
``` ```
> If you want **line numbers**, type `=` after specifying the code block languagues.
> Also, you can specify the start line number. If you want **line numbers**, type `=` after specifying the code block languagues.
> Like below, the line number starts from 101: Also, you can specify the start line number.
Like below, the line number starts from 101:
```javascript=101 ```javascript=101
var s = "JavaScript syntax highlighting"; var s = "JavaScript syntax highlighting";
alert(s); alert(s);
@ -189,44 +205,50 @@ function $initHighlight(block, cls) {
} }
``` ```
> Or you might want to continue the previous code block's line number, use `=+` Or you might want to continue the previous code block's line number, use `=+`:
```javascript=+ ```javascript=+
var s = "JavaScript syntax highlighting"; var s = "JavaScript syntax highlighting";
alert(s); alert(s);
``` ```
> Somtimes you have a super long text without breaks. It's time to use `!` to wrap your code. Somtimes you have a super long text without breaks. It's time to use `!` to wrap your code:
```! ```!
When youre a carpenter making a beautiful chest of drawers, youre not going to use a piece of plywood on the back. When youre a carpenter making a beautiful chest of drawers, youre not going to use a piece of plywood on the back.
``` ```
### Blockquote Tags: ### Blockquote Tags
> Using the syntax below to specifiy your **name, time and color** to vary the blockquotes. > Using the syntax below to specifiy your **name, time and color** to vary the blockquotes.
> [name=ChengHan Wu] [time=Sun, Jun 28, 2015 9:59 PM] [color=#907bf7] > [name=ChengHan Wu] [time=Sun, Jun 28, 2015 9:59 PM] [color=#907bf7]
> > Even support the nest blockquotes! > > Even support nested blockquotes!
> > [name=ChengHan Wu] [time=Sun, Jun 28, 2015 10:00 PM] [color=red] > > [name=Max Mustermann] [time=Sun, Jun 28, 2015 9:47 PM] [color=red]
## Externals ### Externals
#### YouTube
### YouTube
{%youtube aqz-KE-bpKQ %} {%youtube aqz-KE-bpKQ %}
### Vimeo #### Vimeo
{%vimeo 124148255 %} {%vimeo 124148255 %}
### Gist #### Gist
{%gist schacon/4277%} {%gist schacon/4277%}
### SlideShare #### SlideShare
{%slideshare briansolis/26-disruptive-technology-trends-2016-2018-56796196 %} {%slideshare briansolis/26-disruptive-technology-trends-2016-2018-56796196 %}
### PDF #### PDF
**Caution: this might be blocked by your browser if not using an `https` URL.** **Caution: this might be blocked by your browser if not using an `https` URL.**
{%pdf https://papers.nips.cc/paper/5346-sequence-to-sequence-learning-with-neural-networks.pdf %} {%pdf https://papers.nips.cc/paper/5346-sequence-to-sequence-learning-with-neural-networks.pdf %}
## MathJax ### MathJax
You can render *LaTeX* mathematical expressions using **MathJax**, as on [math.stackexchange.com](http://math.stackexchange.com/): You can render *LaTeX* mathematical expressions using **MathJax**, as on [math.stackexchange.com](http://math.stackexchange.com/):
@ -242,9 +264,9 @@ $$
> More information about **LaTeX** mathematical expressions [here](http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference). > More information about **LaTeX** mathematical expressions [here](http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference).
## UML Diagrams ### Diagrams
### Sequence Diagrams #### UML Sequence Diagrams
You can render sequence diagrams like this: You can render sequence diagrams like this:
@ -256,9 +278,12 @@ Note left of Alice: Alice responds
Alice->Bob: Where have you been? Alice->Bob: Where have you been?
``` ```
### Flow Charts More information about **sequence diagrams** syntax [here](http://bramp.github.io/js-sequence-diagrams/).
#### Flow Charts
Flow charts can be specified like this: Flow charts can be specified like this:
```flow ```flow
st=>start: Start st=>start: Start
e=>end: End e=>end: End
@ -271,36 +296,45 @@ cond(yes)->e
cond(no)->op2 cond(no)->op2
``` ```
### Graphviz More information about **flow charts** syntax [here](http://adrai.github.io/flowchart.js/).
#### Graphviz
```graphviz ```graphviz
digraph hierarchy { digraph hierarchy {
nodesep=1.0 // Increases the separation between nodes
nodesep=1.0 // increases the separation between nodes node [color=Red,fontname=Courier,shape=box] // All nodes will this shape and colour
edge [color=Blue, style=dashed] // All the lines look like this
node [color=Red,fontname=Courier,shape=box] //All nodes will this shape and colour Headteacher->{Deputy1 Deputy2 BusinessManager}
edge [color=Blue, style=dashed] //All the lines look like this Deputy1->{Teacher1 Teacher2}
BusinessManager->ITManager
Headteacher->{Deputy1 Deputy2 BusinessManager} {rank=same;ITManager Teacher1 Teacher2} // Put them on the same level
Deputy1->{Teacher1 Teacher2}
BusinessManager->ITManager
{rank=same;ITManager Teacher1 Teacher2} // Put them on the same level
} }
``` ```
### Mermaid More information about **graphviz** syntax [here](http://www.tonyballantyne.com/graphs.html)
#### Mermaid
```mermaid ```mermaid
gantt gantt
title A Gantt Diagram title A Gantt Diagram
section Section section Section
A task :a1, 2014-01-01, 30d A task: a1, 2014-01-01, 30d
Another task :after a1 , 20d Another task: after a1, 20d
section Another
Task in sec :2014-01-12 , 12d section Another
anther task : 24d Task in sec: 2014-01-12, 12d
Another task: 24d
``` ```
### Abc More information about **mermaid** syntax [here](http://knsv.github.io/mermaid)
#### Abc Music Notation
```abc ```abc
X:1 X:1
T:Speed the Plough T:Speed the Plough
@ -313,14 +347,10 @@ GABc dedB|dedB dedB|c2ec B2dB|A2F2 G4:|
g2gf g2Bd|g2f2 e2d2|c2ec B2dB|A2F2 G4:| g2gf g2Bd|g2f2 e2d2|c2ec B2dB|A2F2 G4:|
``` ```
> More information about **sequence diagrams** syntax [here](http://bramp.github.io/js-sequence-diagrams/). More information about **abc** syntax [here](http://abcnotation.com/learn)
> More information about **flow charts** syntax [here](http://adrai.github.io/flowchart.js/).
> More information about **graphviz** syntax [here](http://www.tonyballantyne.com/graphs.html) ### Alert Area
> More information about **mermaid** syntax [here](http://knsv.github.io/mermaid)
> More information about **abc** syntax [here](http://abcnotation.com/learn)
Alert Area
---
:::success :::success
Yes :tada: Yes :tada:
::: :::
@ -337,11 +367,11 @@ Watch out :zap:
Oh No! :fire: Oh No! :fire:
::: :::
## Typography ### Typography
### Headers #### Headers
``` ``` markdown
# h1 Heading # h1 Heading
## h2 Heading ## h2 Heading
### h3 Heading ### h3 Heading
@ -350,7 +380,7 @@ Oh No! :fire:
###### h6 Heading ###### h6 Heading
``` ```
### Horizontal Rules #### Horizontal Rules
___ ___
@ -358,8 +388,7 @@ ___
*** ***
#### Typographic Replacements
### Typographic Replacements
Enable typographer option to see result. Enable typographer option to see result.
@ -375,7 +404,7 @@ Remarkable -- awesome
'Smartypants, single quotes' 'Smartypants, single quotes'
### Emphasis #### Emphasis
**This is bold text** **This is bold text**
@ -397,18 +426,15 @@ Subscript: H~2~O
==Marked text== ==Marked text==
#### Blockquotes
### Blockquotes
> Blockquotes can also be nested... > Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other... >> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows. > > > ...or with spaces between arrows.
#### Lists
### Lists ##### Unordered
#### Unordered
+ Create a list by starting a line with `+`, `-`, or `*` + Create a list by starting a line with `+`, `-`, or `*`
+ Sub-lists are made by indenting 2 spaces: + Sub-lists are made by indenting 2 spaces:
@ -418,27 +444,26 @@ Subscript: H~2~O
- Nulla volutpat aliquam velit - Nulla volutpat aliquam velit
+ Very easy! + Very easy!
#### Ordered ##### Ordered
1. Lorem ipsum dolor sit amet 1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit 2. Consectetur adipiscing elit
3. Integer molestie lorem at massa 3. Aenean commodo ligula eget dolor
1. **You can use sequential numbers...**
1. You can use sequential numbers... 1. **...or keep all the numbers as `1.`**
1. ...or keep all the numbers as `1.` 1. Aenean massa
1. feafw 2. Cum sociis natoque penatibus
2. 332 3. Magnis dis parturient montes
3. 242 4. Nascetur ridiculus mus
4. 2552 1. Donec quam felis
1. e2
Start numbering with offset: Start numbering with offset:
57. foo 57. foo
1. bar 1. bar
### Code #### Code
Inline `code` Inline `code`
@ -449,7 +474,6 @@ Indented code
line 2 of code line 2 of code
line 3 of code line 3 of code
Block code "fences" Block code "fences"
``` ```
@ -466,7 +490,7 @@ var foo = function (bar) {
console.log(foo(5)); console.log(foo(5));
``` ```
### Tables #### Tables
| Option | Description | | Option | Description |
| ------ | ----------- | | ------ | ----------- |
@ -498,26 +522,28 @@ Center aligned columns
| engine | engine to be used for processing templates. Handlebars is the default. | | engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. | | ext | extension to be used for dest files. |
#### Links
### Links [link text](https://demo.codimd.org)
[link text](http://dev.nodeca.com) [link with title](https://nodeca.github.io/pica/demo/ "title text!")
[link with title](http://nodeca.github.io/pica/demo/ "title text!")
Autoconverted link https://github.com/nodeca/pica Autoconverted link https://github.com/nodeca/pica
#### Images
### Images
![Minion](https://octodex.github.com/images/minion.png) ![Minion](https://octodex.github.com/images/minion.png)
With a title:
![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat") ![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")
Like links, Images also have a footnote style syntax
![Alt text][id]
With a reference later in the document defining the URL location:
[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" Like links, images also have a footnote style syntax with a reference later in the document defining the URL location:
![Dojocat][dojoref]
[dojoref]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
Show the image with given size:
![Minion](https://octodex.github.com/images/minion.png =200x200) ![Minion](https://octodex.github.com/images/minion.png =200x200)
Show the image with given size
### Footnotes #### Footnotes
Footnote 1 link[^first]. Footnote 1 link[^first].
Footnote 2 link[^second]. Footnote 2 link[^second].
@ -528,7 +554,7 @@ Duplicated footnote reference[^second].
and multiple paragraphs. and multiple paragraphs.
[^second]: Footnote text. [^second]: Footnote text.
### Definition Lists #### Definition Lists
Term 1 Term 1
@ -552,7 +578,7 @@ Term 2
~ Definition 2a ~ Definition 2a
~ Definition 2b ~ Definition 2b
### Abbreviations #### Abbreviations
This is an HTML abbreviation example. This is an HTML abbreviation example.
It converts "HTML", but keeps intact partial entries like "xxxHTMLyyy" and so on. It converts "HTML", but keeps intact partial entries like "xxxHTMLyyy" and so on.

View file

@ -1,6 +1,16 @@
Release Notes Release Notes
=== ===
<i class="fa fa-tag"></i> 1.3.2 <i class="fa fa-clock-o"></i> 2019-03-28 00:00
---
### Announcement
* CodiMD is now running in an own organization. [Check out our vision for the future](https://github.com/codimd/server/issues/10)
### Fixes
* Update various links to the new repositories
* Fix background color for mode switching button in night mode
<i class="fa fa-tag"></i> 1.3.1 <i class="fa fa-clock-o"></i> 2019-03-23 00:00 <i class="fa fa-tag"></i> 1.3.1 <i class="fa fa-clock-o"></i> 2019-03-23 00:00
--- ---
@ -158,7 +168,7 @@ Release Notes
### Deprecations ### Deprecations
* NodeJS version 6 * NodeJS version 6
* Mattermost login integration (is replaced by [generic oAuth2 module](https://github.com/hackmdio/codimd/blob/6ce7b20a7f92ccff2f7f870ff5d116d685310cfd/docs/guides/auth/mattermost-self-hosted.md)) * Mattermost login integration (is replaced by [generic oAuth2 module](https://github.com/codimd/server/blob/6ce7b20a7f92ccff2f7f870ff5d116d685310cfd/docs/guides/auth/mattermost-self-hosted.md))
### Honorable mentions ### Honorable mentions
* [Alex Hesse (Pingu501)](https://github.com/Pingu501) * [Alex Hesse (Pingu501)](https://github.com/Pingu501)
@ -174,7 +184,7 @@ Release Notes
--- ---
### Announcement ### Announcement
* HackMD CE is renamed to CodiMD to prevent confusion. [For details see here](https://github.com/hackmdio/codimd#hackmd-ce-became-codimd) * HackMD CE is renamed to CodiMD to prevent confusion. [For details see here](https://github.com/codimd/server/tree/master/docs/history.md)
### Enhancements ### Enhancements
* Show full title by hovering over to table of contents entries * Show full title by hovering over to table of contents entries

View file

@ -304,7 +304,6 @@ var editor = editorInstance.init(textit)
// FIXME: global referncing in jquery-textcomplete patch // FIXME: global referncing in jquery-textcomplete patch
window.editor = editor window.editor = editor
var inlineAttach = inlineAttachment.editors.codemirror4.attach(editor)
defaultTextHeight = parseInt($('.CodeMirror').css('line-height')) defaultTextHeight = parseInt($('.CodeMirror').css('line-height'))
// initalize ui reference // initalize ui reference
@ -801,7 +800,6 @@ function changeMode (type) {
editor.getInputField().blur() editor.getInputField().blur()
} }
if (appState.currentMode === modeType.edit || appState.currentMode === modeType.both) { if (appState.currentMode === modeType.edit || appState.currentMode === modeType.both) {
ui.toolbar.uploadImage.fadeIn()
// add and update status bar // add and update status bar
if (!editorInstance.statusBar) { if (!editorInstance.statusBar) {
editorInstance.addStatusBar() editorInstance.addStatusBar()
@ -814,8 +812,6 @@ function changeMode (type) {
// work around foldGutter might not init properly // work around foldGutter might not init properly
editor.setOption('foldGutter', false) editor.setOption('foldGutter', false)
editor.setOption('foldGutter', true) editor.setOption('foldGutter', true)
} else {
ui.toolbar.uploadImage.fadeOut()
} }
if (appState.currentMode !== modeType.edit) { if (appState.currentMode !== modeType.edit) {
$(document.body).css('background-color', 'white') $(document.body).css('background-color', 'white')
@ -1051,17 +1047,6 @@ ui.toolbar.import.snippet.click(function () {
ui.spinner.hide() ui.spinner.hide()
}) })
}) })
// import from clipboard
ui.toolbar.import.clipboard.click(function () {
// na
})
// upload image
ui.toolbar.uploadImage.bind('change', function (e) {
var files = e.target.files || e.dataTransfer.files
e.dataTransfer = {}
e.dataTransfer.files = files
inlineAttach.onDrop(e)
})
// toc // toc
ui.toc.dropdown.click(function (e) { ui.toc.dropdown.click(function (e) {
e.stopPropagation() e.stopPropagation()

View file

@ -138,6 +138,7 @@ export default class Editor {
} }
addToolBar () { addToolBar () {
var inlineAttach = inlineAttachment.editors.codemirror4.attach(this.editor)
this.toolBar = $(toolBarTemplate) this.toolBar = $(toolBarTemplate)
this.toolbarPanel = this.editor.addPanel(this.toolBar[0], { this.toolbarPanel = this.editor.addPanel(this.toolBar[0], {
position: 'top' position: 'top'
@ -157,6 +158,7 @@ export default class Editor {
var makeTable = $('#makeTable') var makeTable = $('#makeTable')
var makeLine = $('#makeLine') var makeLine = $('#makeLine')
var makeComment = $('#makeComment') var makeComment = $('#makeComment')
var uploadImage = $('#uploadImage')
makeBold.click(() => { makeBold.click(() => {
utils.wrapTextWith(this.editor, this.editor, '**') utils.wrapTextWith(this.editor, this.editor, '**')
@ -217,6 +219,13 @@ export default class Editor {
makeComment.click(() => { makeComment.click(() => {
utils.insertText(this.editor, '> []') utils.insertText(this.editor, '> []')
}) })
uploadImage.bind('change', function (e) {
console.log("tiggered")
var files = e.target.files || e.dataTransfer.files
e.dataTransfer = {}
e.dataTransfer.files = files
inlineAttach.onDrop(e)
})
} }
addStatusBar () { addStatusBar () {

View file

@ -34,6 +34,9 @@
<a id="makeImage" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Image"> <a id="makeImage" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Image">
<i class="fa fa-image fa-fw"></i> <i class="fa fa-image fa-fw"></i>
</a> </a>
<span id="uploadImage" class="btn btn-sm btn-dark btn-file ui-upload-image" title="Upload Image">
<i class="fa fa-upload fa-fw"></i><input type="file" accept="image/*" name="upload" multiple>
</span>
<a id="makeTable" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Table"> <a id="makeTable" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Table">
<i class="fa fa-table fa-fw"></i> <i class="fa fa-table fa-fw"></i>
</a> </a>

View file

@ -35,8 +35,7 @@ export const getUIElements = () => ({
edit: $('.ui-edit'), edit: $('.ui-edit'),
view: $('.ui-view'), view: $('.ui-view'),
both: $('.ui-both'), both: $('.ui-both'),
night: $('.ui-night'), night: $('.ui-night')
uploadImage: $('.ui-upload-image')
}, },
infobar: { infobar: {
lastchange: $('.ui-lastchange'), lastchange: $('.ui-lastchange'),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

After

Width:  |  Height:  |  Size: 222 KiB

View file

@ -15,9 +15,6 @@
</div> </div>
<a class="navbar-brand pull-left" href="<%- serverURL %>/"><i class="fa fa-file-text"></i> DepauMD</a> <a class="navbar-brand pull-left" href="<%- serverURL %>/"><i class="fa fa-file-text"></i> DepauMD</a>
<div class="nav-mobile pull-right visible-xs"> <div class="nav-mobile pull-right visible-xs">
<span class="btn btn-link btn-file ui-upload-image" title="Upload Image" style="display:none;">
<i class="fa fa-camera"></i><input type="file" accept="image/*" name="upload" multiple>
</span>
<a data-toggle="dropdown" class="btn btn-link"> <a data-toggle="dropdown" class="btn btn-link">
<i class="fa fa-caret-down"></i> <i class="fa fa-caret-down"></i>
</a> </a>
@ -100,9 +97,6 @@
<span class="btn btn-link btn-file ui-help" title="<%= __('Help') %>" data-toggle="modal" data-target=".help-modal"> <span class="btn btn-link btn-file ui-help" title="<%= __('Help') %>" data-toggle="modal" data-target=".help-modal">
<i class="fa fa-question-circle"></i> <i class="fa fa-question-circle"></i>
</span> </span>
<span class="btn btn-link btn-file ui-upload-image" title="<%= __('Upload Image') %>" style="display:none;">
<i class="fa fa-camera"></i><input type="file" accept="image/*" name="upload" multiple>
</span>
</ul> </ul>
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li id="online-user-list"> <li id="online-user-list">

View file

@ -135,26 +135,26 @@
<option value="ca">Català</option> <option value="ca">Català</option>
<option value="el">Ελληνικά</option> <option value="el">Ελληνικά</option>
<option value="pt">Português</option> <option value="pt">Português</option>
<option value="it">italiano</option> <option value="it">Italiano</option>
<option value="tr">Türkçe</option> <option value="tr">Türkçe</option>
<option value="ru">Русский</option> <option value="ru">Русский</option>
<option value="nl">Nederlands</option> <option value="nl">Nederlands</option>
<option value="hr">hrvatski jezik</option> <option value="hr">Hrvatski</option>
<option value="pl">język polski</option> <option value="pl">Polski</option>
<option value="uk">Українська</option> <option value="uk">Українська</option>
<option value="hi">हिन्दी</option> <option value="hi">हिन्दी</option>
<option value="sv">svenska</option> <option value="sv">Svenska</option>
<option value="eo">Esperanto</option> <option value="eo">Esperanto</option>
<option value="da">dansk</option> <option value="da">Dansk</option>
<option value="ko">한국어</option> <option value="ko">한국어</option>
<option value="id">Bahasa Indonesia</option> <option value="id">Bahasa Indonesia</option>
<option value="sr">српски</option> <option value="sr">Cрпски</option>
</select> </select>
<p> <p>
<%- __('Powered by %s', '<a href="https://codimd.org">CodiMD</a>') %> | <a href="<%- serverURL %>/s/release-notes" target="_blank" rel="noopener"><%= __('Releases') %></a>| <a href="<%- sourceURL %>" target="_blank" rel="noopener"><%= __('Source Code') %></a><% if(privacyStatement) { %> | <a href="<%- serverURL %>/s/privacy" target="_blank" rel="noopener"><%= __('Privacy') %></a><% } %><% if(termsOfUse) { %> | <a href="<%- serverURL %>/s/terms-of-use" target="_blank" rel="noopener"><%= __('Terms of Use') %></a><% } %> <%- __('Powered by %s', '<a href="https://codimd.org">CodiMD</a>') %> | <a href="<%- serverURL %>/s/release-notes" target="_blank" rel="noopener"><%= __('Releases') %></a> | <a href="<%- sourceURL %>" target="_blank" rel="noopener"><%= __('Source Code') %></a><% if(privacyStatement) { %> | <a href="<%- serverURL %>/s/privacy" target="_blank" rel="noopener"><%= __('Privacy') %></a><% } %><% if(termsOfUse) { %> | <a href="<%- serverURL %>/s/terms-of-use" target="_blank" rel="noopener"><%= __('Terms of Use') %></a><% } %>
</p> </p>
<h6 class="social-foot"> <h6 class="social-foot">
<%- __('Follow us on %s and %s.', '<a href="https://github.com/hackmdio/CodiMD" target="_blank" rel="noopener"><i class="fa fa-github"></i> GitHub</a>, <a href="https://riot.im/app/#/room/#codimd:matrix.org" target="_blank" rel="noopener"><i class="fa fa-comments"></i> Riot</a>', '<a href="https://translate.codimd.org" target="_blank" rel="noopener"><i class="fa fa-globe"></i> POEditor</a>') %> <%- __('Follow us on %s and %s.', '<a href="https://github.com/codimd/server" target="_blank" rel="noopener"><i class="fa fa-github"></i> GitHub</a>, <a href="https://riot.im/app/#/room/#codimd:matrix.org" target="_blank" rel="noopener"><i class="fa fa-comments"></i> Riot</a>', '<a href="https://translate.codimd.org" target="_blank" rel="noopener"><i class="fa fa-globe"></i> POEditor</a>') %>
</h6> </h6>
</div> </div>
</div> </div>

View file

@ -15,7 +15,7 @@
<h3 class="panel-title"><%= __('Contacts') %></h3> <h3 class="panel-title"><%= __('Contacts') %></h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<a href="https://github.com/hackmdio/codimd/issues" target="_blank"><i class="fa fa-tag fa-fw"></i> <%= __('Report an issue') %></a> <a href="https://github.com/codimd/server/issues" target="_blank"><i class="fa fa-tag fa-fw"></i> <%= __('Report an issue') %></a>
<br> <br>
<a href="https://riot.im/app/#/room/#codimd:matrix.org" target="_blank"><i class="fa fa-hashtag fa-fw"></i> <%= __('Meet us on %s', 'Matrix') %></a> <a href="https://riot.im/app/#/room/#codimd:matrix.org" target="_blank"><i class="fa fa-hashtag fa-fw"></i> <%= __('Meet us on %s', 'Matrix') %></a>
<br> <br>

View file

@ -19,8 +19,8 @@ describe('generateAvatarURL() gravatar enabled', function () {
}) })
it('should return correct urls', function () { it('should return correct urls', function () {
assert.strictEqual(avatars.generateAvatarURL('Daan Sprenkels', 'hello@dsprenkels.com', true), 'https://www.gravatar.com/avatar/d41b5f3508cc3f31865566a47dd0336b?s=400') assert.strictEqual(avatars.generateAvatarURL('Daan Sprenkels', 'hello@dsprenkels.com', true), 'https://cdn.libravatar.org/avatar/d41b5f3508cc3f31865566a47dd0336b?s=400')
assert.strictEqual(avatars.generateAvatarURL('Daan Sprenkels', 'hello@dsprenkels.com', false), 'https://www.gravatar.com/avatar/d41b5f3508cc3f31865566a47dd0336b?s=96') assert.strictEqual(avatars.generateAvatarURL('Daan Sprenkels', 'hello@dsprenkels.com', false), 'https://cdn.libravatar.org/avatar/d41b5f3508cc3f31865566a47dd0336b?s=96')
}) })
it('should return correct urls for names with spaces', function () { it('should return correct urls for names with spaces', function () {

685
yarn.lock

File diff suppressed because it is too large Load diff