diff options
32 files changed, 422 insertions, 234 deletions
@@ -260,6 +260,7 @@ There are some config settings you need to change in the files below. | `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.* @@ -310,6 +311,7 @@ There are some config settings you need to change in the files below. | `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 @@ -125,7 +125,7 @@ app.use(i18n.init) // routes without sessions // static files -app.use('/', express.static(path.join(__dirname, '/public'), { maxAge: config.staticCacheTime })) +app.use('/', express.static(path.join(__dirname, '/public'), { maxAge: config.staticCacheTime, index: false })) app.use('/docs', express.static(path.resolve(__dirname, config.docsPath), { maxAge: config.staticCacheTime })) app.use('/uploads', express.static(path.resolve(__dirname, config.uploadsPath), { maxAge: config.staticCacheTime })) app.use('/default.md', express.static(path.resolve(__dirname, config.defaultNotePath), { maxAge: config.staticCacheTime })) @@ -175,6 +175,35 @@ app.set('views', config.viewPath) app.engine('ejs', ejs.renderFile) // set view engine app.set('view engine', 'ejs') +// set generally available variables for all views +app.locals.useCDN = config.useCDN +app.locals.serverURL = config.serverURL +app.locals.sourceURL = config.sourceURL +app.locals.allowAnonymous = config.allowAnonymous +app.locals.allowAnonymousEdits = config.allowAnonymousEdits +app.locals.allowPDFExport = config.allowPDFExport +app.locals.authProviders = { + facebook: config.isFacebookEnable, + twitter: config.isTwitterEnable, + github: config.isGitHubEnable, + gitlab: config.isGitLabEnable, + mattermost: config.isMattermostEnable, + dropbox: config.isDropboxEnable, + google: config.isGoogleEnable, + ldap: config.isLDAPEnable, + ldapProviderName: config.ldap.providerName, + saml: config.isSAMLEnable, + oauth2: config.isOAuth2Enable, + oauth2ProviderName: config.oauth2.providerName, + openID: config.isOpenIDEnable, + email: config.isEmailEnable, + allowEmailRegister: config.allowEmailRegister +} + +// Export/Import menu items +app.locals.enableDropBoxSave = config.isDropboxEnable +app.locals.enableGitHubGist = config.isGitHubEnable +app.locals.enableGitlabSnippets = config.isGitlabSnippetsEnable app.use(require('./lib/web/baseRouter')) app.use(require('./lib/web/statusRouter')) diff --git a/bin/manage_users b/bin/manage_users index 74ac1812..8c356200 100755 --- a/bin/manage_users +++ b/bin/manage_users @@ -8,7 +8,8 @@ const models = require("../lib/models/"); const readline = require("readline-sync"); const minimist = require("minimist"); -var usage = ` +function showUsage(tips) { + console.log(`${tips} Command-line utility to create users for email-signin. @@ -16,74 +17,103 @@ Usage: bin/manage_users [--pass password] (--add | --del) user-email Options: --add Add user with the specified user-email --del Delete user with specified user-email + --reset Reset user password with specified user-email --pass Use password from cmdline rather than prompting -` +`); + process.exit(1); +} + +function getPass(argv, action) { + // Find whether we use cmdline or prompt password + if(typeof argv["pass"] !== 'string') { + return readline.question(`Password for ${argv[action]}:`, {hideEchoBack: true}); + } + console.log("Using password from commandline..."); + return argv["pass"]; +} // Using an async function to be able to use await inside async function createUser(argv) { - var existing_user = await models.User.findOne({where: {email: argv["add"]}}); + const existing_user = await models.User.findOne({where: {email: argv["add"]}}); // Cannot create already-existing users if(existing_user != undefined) { - console.log("User with e-mail "+existing_user.email+" already exists! Aborting ..."); + console.log(`User with e-mail ${existing_user.email} already exists! Aborting ...`); process.exit(1); } - // Find whether we use cmdline or prompt password - if(argv["pass"] == undefined) { - var pass = readline.question("Password for "+argv["add"]+":", {hideEchoBack: true}); - } else { - console.log("Using password from commandline..."); - var pass = "" + argv["pass"]; - } + const pass = getPass(argv, "add"); + // Lets try to create, and check success - var ref = await models.User.create({email: argv["add"], password: pass}); + const ref = await models.User.create({email: argv["add"], password: pass}); if(ref == undefined) { - console.log("Could not create user with email "+argv["add"]); + console.log(`Could not create user with email ${argv["add"]}`); process.exit(1); } else - console.log("Created user with email "+argv["add"]); + console.log(`Created user with email ${argv["add"]}`); } // Using an async function to be able to use await inside async function deleteUser(argv) { // Cannot delete non-existing users - var existing_user = await models.User.findOne({where: {email: argv["del"]}}); - if(existing_user == undefined) { - console.log("User with e-mail "+argv["del"]+" does not exist, cannot delete"); + const existing_user = await models.User.findOne({where: {email: argv["del"]}}); + if(existing_user === undefined) { + console.log(`User with e-mail ${argv["del"]} does not exist, cannot delete`); process.exit(1); } // Sadly .destroy() does not return any success value with all // backends. See sequelize #4124 await existing_user.destroy(); - console.log("Deleted user "+argv["del"]+" ..."); + console.log(`Deleted user ${argv["del"]} ...`); } + +// Using an async function to be able to use await inside +async function resetUser(argv) { + const existing_user = await models.User.findOne({where: {email: argv["reset"]}}); + // Cannot reset non-existing users + if(existing_user == undefined) { + console.log(`User with e-mail ${argv["reset"]} does not exist, cannot reset`); + process.exit(1); + } + + const pass = getPass(argv, "reset"); + + // set password and save + existing_user.password = pass; + await existing_user.save(); + console.log(`User with email ${argv["reset"]} password has been reset`); +} + +const options = { + add: createUser, + del: deleteUser, + reset: resetUser, +}; + // Perform commandline-parsing -var argv = minimist(process.argv.slice(2)); +const argv = minimist(process.argv.slice(2)); -// Check for add/delete missing -if (argv["add"] == undefined && argv["del"] == undefined) { - console.log("You did not specify either --add or --del!"); - console.log(usage); - process.exit(1); +const keys = Object.keys(options); +const opts = keys.filter((key) => argv[key] !== undefined); +const action = opts[0]; + +// Check for options missing +if (opts.length === 0) { + showUsage(`You did not specify either ${keys.map((key) => `--${key}`).join(' or ')}!`); } // Check if both are specified -if (argv["add"] != undefined && argv["del"] != undefined) { - console.log("You cannot add and delete at the same time!"); - console.log(usage); - process.exit(1); +if (opts.length > 1) { + showUsage(`You cannot ${action.join(' and ')} at the same time!`); +} +// Check if not string +if (typeof argv[action] !== 'string') { + showUsage(`You must follow an email after --${action}`); } // Call respective processing functions -if (argv["add"] != undefined) { - createUser(argv).then(function() { - process.exit(0); - }); -} else if (argv["del"] != undefined) { - deleteUser(argv).then(function() { - process.exit(0); - }) -} +options[action](argv).then(function() { + process.exit(0); +}); diff --git a/docs/guides/migrate-etherpad.md b/docs/guides/migrate-etherpad.md new file mode 100644 index 00000000..c3783c89 --- /dev/null +++ b/docs/guides/migrate-etherpad.md @@ -0,0 +1,131 @@ +Pad migration guide from etherpad-lite +=== + +The goal of this migration is to do a "dumb" import from all the pads in Etherpad, to notes in +CodiMD. In particular, the url locations of the pads in Etherpad will be lost. Furthermore, any +metadata in Etherpad, such as revisions, author data and also formatted text will not be migrated +to CodiMD (only the plain text contents). + +Note that this guide is not really meant as a support guide. I migrated my own Etherpad to CodiMD, +and it turned out to be quite easy in my opinion. In this guide I share my experience. Stuff may +require some creativity to work properly in your case. When I wrote this guide, I was using +[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 +[CodiMD 1.2.1]: https://github.com/hackmdio/codimd/tree/1.2.1 + +## 0. Requirements + +- `curl` +- running Etherpad server +- running CodiMD server +- [codimd-cli] + +[codimd-cli]: https://github.com/hackmdio/codimd-cli/blob/master/bin/codimd + +## 1. Retrieve the list of pads + +First, compose a list of all the pads that you want to have migrated from your Etherpad. Other than +the admin interface, Etherpad does not have a dedicated function to dump a list of all the pads. +However, the Etherpad wiki explains how to list all the pads by [talking directly to the +database][howtolistallpads]. + +You will end up with a file containing a pad name on each line: + +``` +date-ideas +groceries +london +weddingchecklist +(...) +``` + +[howtolistallpads]: https://github.com/ether/etherpad-lite/wiki/How-to-list-all-pads/49701ecdcbe07aea7ad27ffa23aed0d99c2e17db + +## 2. Run the migration + +Download [codimd-cli] and put the script in the same directory as the file containing the pad names. +Add to this directory the file listed below, I called it `migrate-etherpad.sh`. Modify at least the +configuration settings `ETHERPAD_SERVER` and `CODIMD_SERVER`. + +```shell +#!/bin/sh + +# migrate-etherpad.sh +# +# Description: Migrate pads from etherpad to codimd +# Author: Daan Sprenkels <hello@dsprenkels.com> + +# 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 + +# The base url to where etherpad is hosted +ETHERPAD_SERVER="https://etherpad.example.com" + +# The base url where codimd is hosted +CODIMD_SERVER="https://codimd.example.com" + +# Write a list of pads and the urls which they were migrated to +REDIRECTS_FILE="redirects.txt" + + +# Fail if not called correctly +if (( $# != 1 )); then + echo "Usage: $0 PAD_NAMES_FILE" + exit 2 +fi + +# Do the migration +for PAD_NAME in $1; do + # Download the pad + PAD_FILE="$(mktemp)" + curl "$ETHERPAD_SERVER/p/$PAD_NAME/export/txt" >"$PAD_FILE" + + # Import the pad into codimd + OUTPUT="$(./codimd import "$PAD_FILE")" + echo "$PAD_NAME -> $OUTPUT" >>"$REDIRECTS_FILE" +done +``` + +Call this file like this: + +```shell +./migrate-etherpad.sh pad_names.txt +``` + +This will download all the pads in `pad_names.txt` and put them on CodiMD. They will get assigned +random ids, so you won't be able to find them. The script will save the mappings to a file though +(in my case `redirects.txt`). You can use this file to redirect your users when they visit your +etherpad using a `301 Permanent Redirect` status code (see the next section). + +## 3. Setup redirects (optional) + +I got a `redirects.txt` file that looked a bit like this: + +``` +date-ideas -> Found. Redirecting to https://codimd.example.com/mPt0KfiKSBOTQ3mNcdfn +groceries -> Found. Redirecting to https://codimd.example.com/UukqgwLfhYyUUtARlcJ2_y +london -> Found. Redirecting to https://codimd.example.com/_d3wa-BE8t4Swv5w7O2_9R +weddingchecklist -> Found. Redirecting to https://codimd.example.com/XcQGqlBjl0u40wfT0N8TzQ +(...) +``` + +Using some `sed` magic, I changed it to an nginx config snippet: + +``` +location = /p/date-ideas { + return 301 https://codimd.example.com/mPt0M1KfiKSBOTQ3mNcdfn; +} +location = /p/groceries { + return 301 https://codimd.example.com/UukqgwLfhYyUUtARlcJ2_y; +} +location = /p/london { + return 301 https://codimd.example.com/_d3wa-BE8t4Swv5w7O2_9R; +} +location = /p/weddingchecklist { + return 301 https://codimd.example.com/XcQGqlBjl0u40wfT0N8TzQ; +} +``` + +I put this file into my `etherpad.example.com` nginx config, such that all the users would be +redirected accordingly. diff --git a/lib/config/default.js b/lib/config/default.js index c3ada982..15f11aaa 100644 --- a/lib/config/default.js +++ b/lib/config/default.js @@ -1,5 +1,7 @@ 'use strict' +const os = require('os') + module.exports = { domain: '', urlPath: '', @@ -39,7 +41,7 @@ module.exports = { dhParamPath: '', // other path viewPath: './public/views', - tmpPath: './tmp', + tmpPath: os.tmpdir(), defaultNotePath: './public/default.md', docsPath: './public/docs', uploadsPath: './public/uploads', diff --git a/lib/config/environment.js b/lib/config/environment.js index 6737637c..0c7c9a4f 100644 --- a/lib/config/environment.js +++ b/lib/config/environment.js @@ -3,6 +3,7 @@ const {toBooleanConfig, toArrayConfig, toIntegerConfig} = require('./utils') module.exports = { + sourceURL: process.env.CMD_SOURCE_URL, domain: process.env.CMD_DOMAIN, urlPath: process.env.CMD_URL_PATH, host: process.env.CMD_HOST, diff --git a/lib/config/index.js b/lib/config/index.js index f8b68e30..4e1fa50d 100644 --- a/lib/config/index.js +++ b/lib/config/index.js @@ -8,6 +8,7 @@ const {merge} = require('lodash') const deepFreeze = require('deep-freeze') const {Environment, Permission} = require('./enum') const logger = require('../logger') +const {getGitCommit, getGitHubURL} = require('./utils') const appRootPath = path.resolve(__dirname, '../../') const env = process.env.NODE_ENV || Environment.development @@ -16,11 +17,17 @@ const debugConfig = { } // Get version string from package.json -const {version} = require(path.join(appRootPath, 'package.json')) +const {version, repository} = require(path.join(appRootPath, 'package.json')) + +const commitID = getGitCommit(appRootPath) +const sourceURL = getGitHubURL(repository.url, commitID || version) +const fullversion = commitID ? `${version}-${commitID}` : version const packageConfig = { version: version, - minimumCompatibleVersion: '0.5.0' + minimumCompatibleVersion: '0.5.0', + fullversion: fullversion, + sourceURL: sourceURL } const configFilePath = path.resolve(appRootPath, process.env.CMD_CONFIG_FILE || @@ -110,6 +117,8 @@ if (config.gitlab && config.gitlab.version !== 'v4' && config.gitlab.version !== logger.warn('config.js contains wrong version (' + config.gitlab.version + ') for gitlab api; it should be \'v3\' or \'v4\'. Defaulting to v4') config.gitlab.version = 'v4' } +// If gitlab scope is api, enable snippets Export/import +config.isGitlabSnippetsEnable = (!config.gitlab.scope || config.gitlab.scope === 'api') // Only update i18n files in development setups config.updateI18nFiles = (env === Environment.development) diff --git a/lib/config/utils.js b/lib/config/utils.js index b2406cf1..9646f8c0 100644 --- a/lib/config/utils.js +++ b/lib/config/utils.js @@ -1,5 +1,8 @@ 'use strict' +const fs = require('fs') +const path = require('path') + exports.toBooleanConfig = function toBooleanConfig (configValue) { if (configValue && typeof configValue === 'string') { return (configValue === 'true') @@ -20,3 +23,33 @@ exports.toIntegerConfig = function toIntegerConfig (configValue) { } return configValue } + +exports.getGitCommit = function getGitCommit (repodir) { + if (!fs.existsSync(repodir + '/.git/HEAD')) { + return undefined + } + let reference = fs.readFileSync(repodir + '/.git/HEAD', 'utf8') + if (reference.startsWith('ref: ')) { + reference = reference.substr(5).replace('\n', '') + reference = fs.readFileSync(path.resolve(repodir + '/.git', reference), 'utf8') + } + reference = reference.replace('\n', '') + return reference +} + +exports.getGitHubURL = function getGitHubURL (repo, reference) { + // if it's not a github reference, we handle handle that anyway + if (!repo.startsWith('https://github.com') && !repo.startsWith('git@github.com')) { + return repo + } + if (repo.startsWith('git@github.com') || repo.startsWith('ssh://git@github.com')) { + repo = repo.replace(/^(ssh:\/\/)?git@github.com:/, 'https://github.com/') + } + + if (repo.endsWith('.git')) { + repo = repo.replace(/\.git$/, '/') + } else if (!repo.endsWith('/')) { + repo = repo + '/' + } + return repo + 'tree/' + reference +} diff --git a/lib/realtime.js b/lib/realtime.js index f6c62d4e..8541bafa 100644 --- a/lib/realtime.js +++ b/lib/realtime.js @@ -887,7 +887,7 @@ function connection (socket) { // check version socket.on('version', function () { socket.emit('version', { - version: config.version, + version: config.fullversion, minimumCompatibleVersion: config.minimumCompatibleVersion }) }) diff --git a/lib/response.js b/lib/response.js index a400d021..671aa120 100644 --- a/lib/response.js +++ b/lib/response.js @@ -55,12 +55,10 @@ var response = { function responseError (res, code, detail, msg) { res.status(code).render('error.ejs', { - url: config.serverURL, title: code + ' ' + detail + ' ' + msg, code: code, detail: detail, - msg: msg, - useCDN: config.useCDN + msg: msg }) } @@ -69,26 +67,6 @@ function showIndex (req, res, next) { var deleteToken = '' var data = { - url: config.serverURL, - useCDN: config.useCDN, - allowAnonymous: config.allowAnonymous, - allowAnonymousEdits: config.allowAnonymousEdits, - facebook: config.isFacebookEnable, - twitter: config.isTwitterEnable, - github: config.isGitHubEnable, - gitlab: config.isGitLabEnable, - mattermost: config.isMattermostEnable, - dropbox: config.isDropboxEnable, - google: config.isGoogleEnable, - ldap: config.isLDAPEnable, - ldapProviderName: config.ldap.providerName, - saml: config.isSAMLEnable, - oauth2: config.isOAuth2Enable, - oauth2ProviderName: config.oauth2.providerName, - email: config.isEmailEnable, - allowEmailRegister: config.allowEmailRegister, - allowPDFExport: config.allowPDFExport, - openID: config.isOpenIDEnable, signin: authStatus, infoMessage: req.flash('info'), errorMessage: req.flash('error'), @@ -124,27 +102,7 @@ function responseCodiMD (res, note) { 'X-Robots-Tag': 'noindex, nofollow' // prevent crawling }) res.render('codimd.ejs', { - url: config.serverURL, - title: title, - useCDN: config.useCDN, - allowAnonymous: config.allowAnonymous, - allowAnonymousEdits: config.allowAnonymousEdits, - facebook: config.isFacebookEnable, - twitter: config.isTwitterEnable, - github: config.isGitHubEnable, - gitlab: config.isGitLabEnable, - mattermost: config.isMattermostEnable, - dropbox: config.isDropboxEnable, - google: config.isGoogleEnable, - ldap: config.isLDAPEnable, - ldapProviderName: config.ldap.providerName, - oauth2ProviderName: config.oauth2.providerName, - saml: config.isSAMLEnable, - oauth2: config.isOAuth2Enable, - email: config.isEmailEnable, - allowEmailRegister: config.allowEmailRegister, - allowPDFExport: config.allowPDFExport, - openID: config.isOpenIDEnable + title: title }) } @@ -254,16 +212,13 @@ function showPublishNote (req, res, next) { var updatetime = note.lastchangeAt var title = models.Note.decodeTitle(note.title) title = models.Note.generateWebTitle(meta.title || title) - var origin = config.serverURL var data = { title: title, description: meta.description || (markdown ? models.Note.generateDescription(markdown) : null), viewcount: note.viewcount, createtime: createtime, updatetime: updatetime, - url: origin, body: body, - useCDN: config.useCDN, owner: note.owner ? note.owner.id : null, ownerprofile: note.owner ? models.User.getProfile(note.owner) : null, lastchangeuser: note.lastchangeuser ? note.lastchangeuser.id : null, @@ -637,18 +592,15 @@ function showPublishSlide (req, res, next) { var updatetime = note.lastchangeAt var title = models.Note.decodeTitle(note.title) title = models.Note.generateWebTitle(meta.title || title) - var origin = config.serverURL var data = { title: title, description: meta.description || (markdown ? models.Note.generateDescription(markdown) : null), viewcount: note.viewcount, createtime: createtime, updatetime: updatetime, - url: origin, body: markdown, theme: meta.slideOptions && utils.isRevealTheme(meta.slideOptions.theme), meta: JSON.stringify(extracted.meta), - useCDN: config.useCDN, owner: note.owner ? note.owner.id : null, ownerprofile: note.owner ? models.User.getProfile(note.owner) : null, lastchangeuser: note.lastchangeuser ? note.lastchangeuser.id : null, diff --git a/lib/web/statusRouter.js b/lib/web/statusRouter.js index fb2609ea..2b9cb65f 100644 --- a/lib/web/statusRouter.js +++ b/lib/web/statusRouter.js @@ -96,7 +96,7 @@ statusRouter.get('/config', function (req, res) { domain: config.domain, urlpath: config.urlPath, debug: config.debug, - version: config.version, + version: config.fullversion, DROPBOX_APP_KEY: config.dropbox.appKey, allowedUploadMimeTypes: config.allowedUploadMimeTypes } diff --git a/locales/en.json b/locales/en.json index 100f4f54..ead7ce2f 100644 --- a/locales/en.json +++ b/locales/en.json @@ -112,5 +112,6 @@ "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.", "Delete user": "Delete user", "Export user data": "Export user data", - "Help us translating on %s": "Help us translating on %s" -}
\ No newline at end of file + "Help us translating on %s": "Help us translating on %s", + "Source Code": "Source Code" +} diff --git a/locales/fr.json b/locales/fr.json index 0784daa5..7d4aa8e1 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -30,7 +30,7 @@ "Releases": "Versions", "Are you sure?": "Ëtes-vous sûr ?", "Do you really want to delete this note?": "Voulez-vous vraiment supprimer cette note?", - "All users will lose their connection.": "All users will lose their connection.", + "All users will lose their connection.": "Tous les utilisateurs perdront leur connexion.", "Cancel": "Annuler", "Yes, do it!": "Oui, je suis sûr !", "Choose method": "Choisir la méthode", @@ -109,7 +109,8 @@ "Privacy": "Confidentialité", "Terms of Use": "Conditions d'utilisation", "Do you really want to delete your user account?": "Voulez-vous vraiment supprimer votre compte utilisateur", - "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.": "Cela supprimera votre compte, toutes les notes dont vous êtes propriétaire et supprimera toute référence à votre compte dans les autres notes.", "Delete user": "Suprrimez l'utilisteur", - "Export user data": "Exportez les données utilisateur" + "Export user data": "Exportez les données utilisateur", + "Help us translating on %s": "" }
\ No newline at end of file diff --git a/locales/it.json b/locales/it.json index 207f3e7e..8a7f9ee5 100644 --- a/locales/it.json +++ b/locales/it.json @@ -111,5 +111,6 @@ "Do you really want to delete your user account?": "Vuoi veramente cancellare il tuo account utente?", "This will delete your account, all notes that are owned by you and remove all references to your account from other notes.": "Questo cancellerà il tuo account, tutte le note di cui sei proprietario e rimuoverà i riferimenti al tuo account dalle altre note.", "Delete user": "Elimina utente", - "Export user data": "Esporta dati utente" + "Export user data": "Esporta dati utente", + "Help us translating on %s": "Aiutaci nella traduzione su %s" }
\ No newline at end of file diff --git a/package.json b/package.json index 524f87e9..304a526d 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "Idle.Js": "git+https://github.com/shawnmclean/Idle.js", "archiver": "^2.1.1", "async": "^2.1.4", - "aws-sdk": "^2.7.20", + "aws-sdk": "^2.345.0", "azure-storage": "^2.7.0", "base64url": "^3.0.0", "blueimp-md5": "^2.6.0", @@ -62,7 +62,7 @@ "jsdom-nogyp": "^0.8.3", "keymaster": "^1.6.2", "list.js": "^1.5.0", - "lodash": "^4.17.4", + "lodash": "^4.17.11", "lz-string": "git+https://github.com/hackmdio/lz-string.git", "markdown-it": "^8.2.2", "markdown-it-abbr": "^1.0.4", @@ -98,7 +98,7 @@ "passport-ldapauth": "^2.0.0", "passport-local": "^1.0.0", "passport-oauth2": "^1.4.0", - "passport-saml": "^0.31.0", + "passport-saml": "^0.35.0", "passport-twitter": "^1.0.4", "passport.socketio": "^3.7.0", "pdfobject": "^2.0.201604172", @@ -108,7 +108,7 @@ "randomcolor": "^0.5.3", "raphael": "git+https://github.com/dmitrybaranovskiy/raphael", "readline-sync": "^1.4.7", - "request": "^2.79.0", + "request": "^2.88.0", "reveal.js": "~3.6.0", "scrypt": "^6.0.3", "select2": "^3.5.2-browserify", diff --git a/public/docs/features.md b/public/docs/features.md index 3d790039..31c08d2e 100644 --- a/public/docs/features.md +++ b/public/docs/features.md @@ -88,9 +88,23 @@ You can hover and click <i class="fa fa-chain"></i> to anchor on it. 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) +- emacs +- vim + ## Shortcut Keys: -Just like Sublime text, which is pretty quick and convenient. -> For more infomation, see [here](https://codemirror.net/demo/sublime.html). +The shortcut keys depend on your selected editor mode. By default they are just like Sublime text, which is pretty quick and convenient. +> For more information, see [here](https://codemirror.net/demo/sublime.html). + +For emacs: +> For more information, see [here](https://codemirror.net/demo/emacs.html). + +For vim: +> For more information, see [here](https://codemirror.net/demo/vim.html). ## Auto-Complete: This editor provides full auto-complete hints in markdown. diff --git a/public/js/extra.js b/public/js/extra.js index ddec31a8..ed1470be 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -1147,15 +1147,14 @@ const pdfPlugin = new Plugin( const emojijsPlugin = new Plugin( // regexp to match emoji shortcodes :something: - /:([\d\D]*):/, + // We generate an universal regex that guaranteed only contains the + // emojies we have available. This should prevent all false-positives + new RegExp(':(' + window.emojify.emojiNames.map((item) => { return RegExp.escape(item) }).join('|') + '):', 'i'), (match, utils) => { - const emoji = match[1] ? match[1].toLowerCase() : undefined - if (window.emojify.emojiNames.includes(emoji)) { - const div = $(`<img class="emoji" src="${serverurl}/build/emojify.js/dist/images/basic/${emoji}.png"></img>`) - return div[0].outerHTML - } - return match[0] + const emoji = match[1].toLowerCase() + const div = $(`<img class="emoji" src="${serverurl}/build/emojify.js/dist/images/basic/${emoji}.png"></img>`) + return div[0].outerHTML } ) diff --git a/public/js/render.js b/public/js/render.js index 23b8934e..ff5e2bf2 100644 --- a/public/js/render.js +++ b/public/js/render.js @@ -1,6 +1,8 @@ /* eslint-env browser, jquery */ -/* global filterXSS */ // allow some attributes + +var filterXSS = require('xss') + var whiteListAttr = ['id', 'class', 'style'] window.whiteListAttr = whiteListAttr // allow link starts with '.', '/' and custom protocol with '://', exclude link starts with javascript:// @@ -71,5 +73,6 @@ function preventXSS (html) { window.preventXSS = preventXSS module.exports = { - preventXSS: preventXSS + preventXSS: preventXSS, + escapeAttrValue: filterXSS.escapeAttrValue } diff --git a/public/js/reveal-markdown.js b/public/js/reveal-markdown.js index d15b5ebd..ad5bfd04 100644 --- a/public/js/reveal-markdown.js +++ b/public/js/reveal-markdown.js @@ -1,6 +1,6 @@ /* eslint-env browser, jquery */ -import { preventXSS } from './render' +import { preventXSS, escapeAttrValue } from './render' import { md } from './extra' /** @@ -259,7 +259,7 @@ import { md } from './extra' while ((matchesClass = mardownClassRegex.exec(classes))) { var name = matchesClass[1] var value = matchesClass[2] - if (name.substr(0, 5) === 'data-' || window.whiteListAttr.indexOf(name) !== -1) { elementTarget.setAttribute(name, window.filterXSS.escapeAttrValue(value)) } + if (name.substr(0, 5) === 'data-' || window.whiteListAttr.indexOf(name) !== -1) { elementTarget.setAttribute(name, escapeAttrValue(value)) } } return true } diff --git a/public/views/codimd/foot.ejs b/public/views/codimd/foot.ejs index 000ccb6d..9b1c68d6 100644 --- a/public/views/codimd/foot.ejs +++ b/public/views/codimd/foot.ejs @@ -1,4 +1,4 @@ -<script src="<%= url %>/js/mathjax-config-extra.js"></script> +<script src="<%= serverURL %>/js/mathjax-config-extra.js"></script> <% if(useCDN) { %> <script src="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js" integrity="sha256-PieqE0QdEDMppwXrTzSZQr6tWFX3W5KkyRVyF1zN3eg=" crossorigin="anonymous" defer></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script> @@ -21,7 +21,7 @@ <script src="https://cdnjs.cloudflare.com/ajax/libs/abcjs/3.1.1/abcjs_basic-min.js" integrity="sha256-Sq1r2XXWXQoShQKsS0Wrf5r7fRkErd9Fat9vHYeU68s=" crossorigin="anonymous"></script> <%- include ../build/index-scripts %> <% } else { %> -<script src="<%- url %>/build/MathJax/MathJax.js" defer></script> -<script src="<%- url %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script> +<script src="<%- serverURL %>/build/MathJax/MathJax.js" defer></script> +<script src="<%- serverURL %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script> <%- include ../build/index-pack-scripts %> <% } %> diff --git a/public/views/codimd/head.ejs b/public/views/codimd/head.ejs index 356ded6d..afa89d13 100644 --- a/public/views/codimd/head.ejs +++ b/public/views/codimd/head.ejs @@ -5,8 +5,8 @@ <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="mobile-web-app-capable" content="yes"> <title><%= title %></title> -<link rel="icon" type="image/png" href="<%- url %>/favicon.png"> -<link rel="apple-touch-icon" href="<%- url %>/apple-touch-icon.png"> +<link rel="icon" type="image/png" href="<%- serverURL %>/favicon.png"> +<link rel="apple-touch-icon" href="<%- serverURL %>/apple-touch-icon.png"> <% if(useCDN) { %> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fork-awesome/1.1.3/css/fork-awesome.min.css" integrity="sha256-ZhApazu+kejqTYhMF+1DzNKjIzP7KXu6AzyXcC1gMus=" crossorigin="anonymous" /> @@ -16,6 +16,6 @@ <%- include ../build/index-header %> <%- include ../shared/polyfill %> <% } else { %> -<link rel="stylesheet" href='<%- url %>/build/emojify.js/dist/css/basic/emojify.min.css'> +<link rel="stylesheet" href='<%- serverURL %>/build/emojify.js/dist/css/basic/emojify.min.css'> <%- include ../build/index-pack-header %> <% } %> diff --git a/public/views/codimd/header.ejs b/public/views/codimd/header.ejs index 1b5e4222..b83838ea 100644 --- a/public/views/codimd/header.ejs +++ b/public/views/codimd/header.ejs @@ -13,7 +13,7 @@ <ul class="dropdown-menu list" role="menu" aria-labelledby="menu"> </ul> </div> - <a class="navbar-brand pull-left" href="<%- url %>/"><i class="fa fa-file-text"></i> CodiMD</a> + <a class="navbar-brand pull-left" href="<%- serverURL %>/"><i class="fa fa-file-text"></i> CodiMD</a> <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> @@ -22,7 +22,7 @@ <i class="fa fa-caret-down"></i> </a> <ul class="dropdown-menu list" role="menu" aria-labelledby="menu"> - <li role="presentation"><a role="menuitem" class="ui-new" tabindex="-1" href="<%- url %>/new" target="_blank" rel="noopener"><i class="fa fa-plus fa-fw"></i> <%= __('New') %></a> + <li role="presentation"><a role="menuitem" class="ui-new" tabindex="-1" href="<%- serverURL %>/new" target="_blank" rel="noopener"><i class="fa fa-plus fa-fw"></i> <%= __('New') %></a> </li> <li role="presentation"><a role="menuitem" class="ui-publish" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-share-square-o fa-fw"></i> <%= __('Publish') %></a> </li> @@ -32,16 +32,16 @@ </li> <li role="presentation"><a role="menuitem" class="ui-extra-slide" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-tv fa-fw"></i> <%= __('Slide Mode') %></a> </li> - <% if((typeof github !== 'undefined' && github) || (typeof dropbox !== 'undefined' && dropbox) || (typeof gitlab !== 'undefined' && gitlab && (!gitlab.scope || gitlab.scope === 'api'))) { %> + <% if(enableGitHubGist || enableDropBoxSave || enableGitlabSnippets) { %> <li class="divider"></li> <li class="dropdown-header"><%= __('Export') %></li> <li role="presentation"><a role="menuitem" class="ui-save-dropbox" tabindex="-1" href="#" target="_self"><i class="fa fa-dropbox fa-fw"></i> Dropbox</a> </li> - <% if(typeof github !== 'undefined' && github) { %> + <% if(enableGitHubGist) { %> <li role="presentation"><a role="menuitem" class="ui-save-gist" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-github fa-fw"></i> Gist</a> </li> <% } %> - <% if(typeof gitlab !== 'undefined' && gitlab && (!gitlab.scope || gitlab.scope === 'api')) { %> + <% if(enableGitlabSnippets) { %> <li role="presentation"><a role="menuitem" class="ui-save-snippet" href="#"><i class="fa fa-gitlab fa-fw"></i> Snippet</a> </li> <% } %> @@ -52,7 +52,7 @@ </li> <li role="presentation"><a role="menuitem" class="ui-import-gist" href="#" data-toggle="modal" data-target="#gistImportModal"><i class="fa fa-github fa-fw"></i> Gist</a> </li> - <% if(typeof gitlab !== 'undefined' && gitlab && (!gitlab.scope || gitlab.scope === 'api')) { %> + <% if(enableGitlabSnippets) { %> <li role="presentation"><a role="menuitem" class="ui-import-snippet" href="#"><i class="fa fa-gitlab fa-fw"></i> Snippet</a> </li> <% } %> @@ -115,7 +115,7 @@ </ul> <ul class="nav navbar-nav navbar-right" style="padding:0;"> <li> - <a href="<%- url %>/new" target="_blank" rel="noopener" class="ui-new"> + <a href="<%- serverURL %>/new" target="_blank" rel="noopener" class="ui-new"> <i class="fa fa-plus"></i> <%= __('New') %> </a> </li> @@ -134,16 +134,16 @@ </li> <li role="presentation"><a role="menuitem" class="ui-extra-slide" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-tv fa-fw"></i> <%= __('Slide Mode') %></a> </li> - <% if((typeof github !== 'undefined' && github) || (typeof dropbox !== 'undefined' && dropbox) || (typeof gitlab !== 'undefined' && gitlab && (!gitlab.scope || gitlab.scope === 'api'))) { %> + <% if(enableGitHubGist || enableDropBoxSave || enableGitlabSnippets) { %> <li class="divider"></li> <li class="dropdown-header"><%= __('Export') %></li> <li role="presentation"><a role="menuitem" class="ui-save-dropbox" tabindex="-1" href="#" target="_self"><i class="fa fa-dropbox fa-fw"></i> Dropbox</a> </li> - <% if(typeof github !== 'undefined' && github) { %> + <% if(enableGitHubGist) { %> <li role="presentation"><a role="menuitem" class="ui-save-gist" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-github fa-fw"></i> Gist</a> </li> <% } %> - <% if(typeof gitlab !== 'undefined' && gitlab && (!gitlab.scope || gitlab.scope === 'api')) { %> + <% if(enableGitlabSnippets) { %> <li role="presentation"><a role="menuitem" class="ui-save-snippet" href="#"><i class="fa fa-gitlab fa-fw"></i> Snippet</a> </li> <% } %> @@ -154,7 +154,7 @@ </li> <li role="presentation"><a role="menuitem" class="ui-import-gist" href="#" data-toggle="modal" data-target="#gistImportModal"><i class="fa fa-github fa-fw"></i> Gist</a> </li> - <% if(typeof gitlab !== 'undefined' && gitlab && (!gitlab.scope || gitlab.scope === 'api')) { %> + <% if(enableGitlabSnippets) { %> <li role="presentation"><a role="menuitem" class="ui-import-snippet" href="#"><i class="fa fa-gitlab fa-fw"></i> Snippet</a> </li> <% } %> diff --git a/public/views/error.ejs b/public/views/error.ejs index 98c3c74e..3ed76c8c 100644 --- a/public/views/error.ejs +++ b/public/views/error.ejs @@ -3,14 +3,14 @@ <head> <%- include codimd/head %> - <link rel="stylesheet" href="<%- url %>/css/center.css"> + <link rel="stylesheet" href="<%- serverURL %>/css/center.css"> </head> <body> <%- include codimd/header %> <div class="container-fluid text-center"> <div class="vertical-center-row"> - <h1><%- code %> <%- detail %> <small><%- msg %></small></h1> + <h1><%- code %> <%- detail %> <small><%- msg %></small></h1> </div> </div> <%- include codimd/footer %> diff --git a/public/views/index/body.ejs b/public/views/index/body.ejs index 18bffddb..43582d78 100644 --- a/public/views/index/body.ejs +++ b/public/views/index/body.ejs @@ -12,24 +12,24 @@ <li class="ui-history<% if(signin) { %> active<% } %>"><a href="#"><%= __('History') %></a> </li> <div class="ui-signin" style="float: right; margin-top: 8px;<% if(signin) { %> display: none;<% } %>"> - <% if(allowAnonymous) { %> - <a type="button" href="<%- url %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New guest note') %></a> + <% if (allowAnonymous) { %> + <a type="button" href="<%- serverURL %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New guest note') %></a> <% } %> - <% if(facebook || twitter || github || gitlab || mattermost || dropbox || google || ldap || saml || oauth2 || email) { %> + <% if (authProviders.facebook || authProviders.twitter || authProviders.github || authProviders.gitlab || authProviders.mattermost || authProviders.dropbox || authProviders.google || authProviders.ldap || authProviders.saml || authProviders.oauth2 || authProviders.email) { %> <button class="btn btn-sm btn-success ui-signin" data-toggle="modal" data-target=".signin-modal"><%= __('Sign In') %></button> <% } %> </div> <div class="ui-signout" style="float: right; margin-top: 8px;<% if(!signin) { %> display: none;<% } %>"> - <a type="button" href="<%- url %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New note') %></a> + <a type="button" href="<%- serverURL %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New note') %></a> <span class="ui-profile dropdown pull-right"> <button id="profileLabel" class="btn btn-sm btn-link ui-profile-label" style="padding-right: 0;" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <img class="ui-avatar" width="20" height="20"><span class="hidden-xs hidden-sm"> <span class="ui-name"></span></span> <i class="fa fa-caret-down"></i> </button> <ul class="dropdown-menu" aria-labelledby="profileLabel"> - <li><a href="<%- url %>/features"><i class="fa fa-dot-circle-o fa-fw"></i> <%= __('Features') %></a></li> - <li><a href="<%- url %>/me/export"><i class="fa fa-cloud-download fa-fw"></i> <%= __('Export user data') %></a></li> + <li><a href="<%- serverURL %>/features"><i class="fa fa-dot-circle-o fa-fw"></i> <%= __('Features') %></a></li> + <li><a href="<%- serverURL %>/me/export"><i class="fa fa-cloud-download fa-fw"></i> <%= __('Export user data') %></a></li> <li><a class="ui-delete-user" data-toggle="modal" data-target=".delete-user-modal"><i class="fa fa-trash fa-fw"></i> <%= __('Delete user') %></a></li> - <li><a href="<%- url %>/logout"><i class="fa fa-sign-out fa-fw"></i> <%= __('Sign Out') %></a></li> + <li><a href="<%- serverURL %>/logout"><i class="fa fa-sign-out fa-fw"></i> <%= __('Sign Out') %></a></li> </ul> </span> </div> @@ -50,7 +50,7 @@ <% if (errorMessage && errorMessage.length > 0) { %> <div class="alert alert-danger" style="max-width: 400px; margin: 0 auto;"><%= errorMessage %></div> <% } %> - <% if(facebook || twitter || github || gitlab || mattermost || dropbox || google || ldap || saml || oauth2 || email) { %> + <% if (authProviders.facebook || authProviders.twitter || authProviders.github || authProviders.gitlab || authProviders.mattermost || authProviders.dropbox || authProviders.google || authProviders.ldap || authProviders.saml || authProviders.oauth2 || authProviders.email) { %> <span class="ui-signin"> <br> <a type="button" class="btn btn-lg btn-success ui-signin" data-toggle="modal" data-target=".signin-modal" style="min-width: 200px;"><%= __('Sign In') %></a> @@ -58,26 +58,26 @@ <span class="ui-or"><%= __('or') %></span> <% } %> <span class="ui-signin"> - <a type="button" href="<%- url %>/features" class="btn btn-lg btn-primary" style="min-width: 200px;"><%= __('Explore all features') %></a> + <a type="button" href="<%- serverURL %>/features" class="btn btn-lg btn-primary" style="min-width: 200px;"><%= __('Explore all features') %></a> <br> <br> - <img src="<%- url %>/screenshot.png" class="screenshot ui-signin"> + <img src="<%- serverURL %>/screenshot.png" class="screenshot ui-signin"> </span> <div class="lead row" style="width: 90%; margin: 0 auto;"> <div class="col-md-4 inner"> - <a href="<%- url %>/features#share-notes"> + <a href="<%- serverURL %>/features#share-notes"> <i class="fa fa-bolt fa-3x"></i> <h4><%= __('Collaborate with URL') %></h4> </a> </div> <div class="col-md-4 inner"> - <a href="<%- url %>/features#mathjax"> + <a href="<%- serverURL %>/features#mathjax"> <i class="fa fa-bar-chart fa-3x"></i> <h4><%= __('Support charts and MathJax') %></h4> </a> </div> <div class="col-md-4 inner"> - <a href="<%- url %>/features#slide-mode"> + <a href="<%- serverURL %>/features#slide-mode"> <i class="fa fa-tv fa-3x"></i> <h4><%= __('Support slide mode') %></h4> </a> @@ -150,7 +150,7 @@ <option value="id">Bahasa Indonesia</option> </select> <p> - Powered by <a href="https://codimd.org">CodiMD</a> | <a href="<%- url %>/s/release-notes" target="_blank" rel="noopener"><%= __('Releases') %></a><% if(privacyStatement) { %> | <a href="<%- url %>/s/privacy" target="_blank" rel="noopener"><%= __('Privacy') %></a><% } %><% if(termsOfUse) { %> | <a href="<%- url %>/s/terms-of-use" target="_blank" rel="noopener"><%= __('Terms of Use') %></a><% } %> + Powered by <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> <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>') %> @@ -195,7 +195,7 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-default ui-delete-user-modal-cancel" data-dismiss="modal"><%= __('Cancel') %></button> - <a type="button" class="btn btn-danger" href="<%- url %>/me/delete/<%- deleteToken %>"><%= __('Yes, do it!') %></a> + <a type="button" class="btn btn-danger" href="<%- serverURL %>/me/delete/<%- deleteToken %>"><%= __('Yes, do it!') %></a> </div> </div> </div> diff --git a/public/views/index/head.ejs b/public/views/index/head.ejs index fc10dfa0..7a601bdf 100644 --- a/public/views/index/head.ejs +++ b/public/views/index/head.ejs @@ -7,8 +7,8 @@ <meta name="description" content="<%= __('Best way to write and share your knowledge in markdown.') %>"> <meta name="keywords" content="Collaborative, Markdown, Notes"> <title>CodiMD - <%= __('Collaborative markdown notes') %></title> -<link rel="icon" type="image/png" href="<%- url %>/favicon.png"> -<link rel="apple-touch-icon" href="<%- url %>/apple-touch-icon.png"> +<link rel="icon" type="image/png" href="<%- serverURL %>/favicon.png"> +<link rel="apple-touch-icon" href="<%- serverURL %>/apple-touch-icon.png"> <% if(useCDN) { %> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fork-awesome/1.1.3/css/fork-awesome.min.css" integrity="sha256-ZhApazu+kejqTYhMF+1DzNKjIzP7KXu6AzyXcC1gMus=" crossorigin="anonymous" /> diff --git a/public/views/pretty.ejs b/public/views/pretty.ejs index a087be7f..ff4dcc23 100644 --- a/public/views/pretty.ejs +++ b/public/views/pretty.ejs @@ -15,8 +15,8 @@ <meta name="description" content="<%= description %>"> <% } %> <title><%= title %></title> - <link rel="icon" type="image/png" href="<%- url %>/favicon.png"> - <link rel="apple-touch-icon" href="<%- url %>/apple-touch-icon.png"> + <link rel="icon" type="image/png" href="<%- serverURL %>/favicon.png"> + <link rel="apple-touch-icon" href="<%- serverURL %>/apple-touch-icon.png"> <% if(useCDN) { %> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fork-awesome/1.1.3/css/fork-awesome.min.css" integrity="sha256-ZhApazu+kejqTYhMF+1DzNKjIzP7KXu6AzyXcC1gMus=" crossorigin="anonymous" /> @@ -25,7 +25,7 @@ <%- include build/pretty-header %> <%- include shared/polyfill %> <% } else { %> - <link rel="stylesheet" href='<%- url %>/build/emojify.js/dist/css/basic/emojify.min.css'> + <link rel="stylesheet" href='<%- serverURL %>/build/emojify.js/dist/css/basic/emojify.min.css'> <%- include build/pretty-pack-header %> <% } %> </head> @@ -71,7 +71,7 @@ </body> </html> -<script src="<%= url %>/js/mathjax-config-extra.js"></script> +<script src="<%= serverURL %>/js/mathjax-config-extra.js"></script> <% if(useCDN) { %> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.0/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script> @@ -90,8 +90,8 @@ <script src="https://cdnjs.cloudflare.com/ajax/libs/abcjs/3.1.1/abcjs_basic-min.js" integrity="sha256-Sq1r2XXWXQoShQKsS0Wrf5r7fRkErd9Fat9vHYeU68s=" crossorigin="anonymous"></script> <%- include build/pretty-scripts %> <% } else { %> -<script src="<%- url %>/build/MathJax/MathJax.js" defer></script> -<script src="<%- url %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script> +<script src="<%- serverURL %>/build/MathJax/MathJax.js" defer></script> +<script src="<%- serverURL %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script> <%- include build/pretty-pack-scripts %> <% } %> <%- include shared/ga %> diff --git a/public/views/shared/refresh-modal.ejs b/public/views/shared/refresh-modal.ejs index 64580545..2aa652aa 100644 --- a/public/views/shared/refresh-modal.ejs +++ b/public/views/shared/refresh-modal.ejs @@ -14,7 +14,7 @@ </div> <div class="new-version" style="display:none;"> <h5><%= __('New version available!') %></h5> - <a href="<%- url %>/s/release-notes" target="_blank" rel="noopener"><%= __('See releases notes here') %></a> + <a href="<%- serverURL %>/s/release-notes" target="_blank" rel="noopener"><%= __('See releases notes here') %></a> <br> <strong><%= __('Refresh to enjoy new features.') %></strong> </div> @@ -28,4 +28,4 @@ </div> </div> </div> -</div>
\ No newline at end of file +</div> diff --git a/public/views/shared/signin-modal.ejs b/public/views/shared/signin-modal.ejs index b413511c..d46b8d54 100644 --- a/public/views/shared/signin-modal.ejs +++ b/public/views/shared/signin-modal.ejs @@ -8,56 +8,56 @@ <h4 class="modal-title" id="mySmallModalLabel"><%= __('Choose method') %></h4> </div> <div class="modal-body" style="text-align: center;"> - <% if(facebook) { %> - <a href="<%- url %>/auth/facebook" class="btn btn-lg btn-block btn-social btn-facebook"> + <% if (authProviders.facebook) { %> + <a href="<%- serverURL %>/auth/facebook" class="btn btn-lg btn-block btn-social btn-facebook"> <i class="fa fa-facebook"></i> <%= __('Sign in via %s', 'Facebook') %> </a> <% } %> - <% if(twitter) { %> - <a href="<%- url %>/auth/twitter" class="btn btn-lg btn-block btn-social btn-twitter"> + <% if (authProviders.twitter) { %> + <a href="<%- serverURL %>/auth/twitter" class="btn btn-lg btn-block btn-social btn-twitter"> <i class="fa fa-twitter"></i> <%= __('Sign in via %s', 'Twitter') %> </a> <% } %> - <% if(github) { %> - <a href="<%- url %>/auth/github" class="btn btn-lg btn-block btn-social btn-github"> + <% if (authProviders.github) { %> + <a href="<%- serverURL %>/auth/github" class="btn btn-lg btn-block btn-social btn-github"> <i class="fa fa-github"></i> <%= __('Sign in via %s', 'GitHub') %> </a> <% } %> - <% if(gitlab) { %> - <a href="<%- url %>/auth/gitlab" class="btn btn-lg btn-block btn-social btn-soundcloud"> + <% if (authProviders.gitlab) { %> + <a href="<%- serverURL %>/auth/gitlab" class="btn btn-lg btn-block btn-social btn-soundcloud"> <i class="fa fa-gitlab"></i> <%= __('Sign in via %s', 'GitLab') %> </a> <% } %> - <% if(mattermost) { %> - <a href="<%- url %>/auth/mattermost" class="btn btn-lg btn-block btn-social btn-soundcloud"> + <% if (authProviders.mattermost) { %> + <a href="<%- serverURL %>/auth/mattermost" class="btn btn-lg btn-block btn-social btn-soundcloud"> <i class="fa fa-mattermost"></i> <%= __('Sign in via %s', 'Mattermost') %> </a> <% } %> - <% if(dropbox) { %> - <a href="<%- url %>/auth/dropbox" class="btn btn-lg btn-block btn-social btn-dropbox"> + <% if (authProviders.dropbox) { %> + <a href="<%- serverURL %>/auth/dropbox" class="btn btn-lg btn-block btn-social btn-dropbox"> <i class="fa fa-dropbox"></i> <%= __('Sign in via %s', 'Dropbox') %> </a> <% } %> - <% if(google) { %> - <a href="<%- url %>/auth/google" class="btn btn-lg btn-block btn-social btn-google"> + <% if (authProviders.google) { %> + <a href="<%- serverURL %>/auth/google" class="btn btn-lg btn-block btn-social btn-google"> <i class="fa fa-google"></i> <%= __('Sign in via %s', 'Google') %> </a> <% } %> - <% if(saml) { %> - <a href="<%- url %>/auth/saml" class="btn btn-lg btn-block btn-social btn-success"> + <% if (authProviders.saml) { %> + <a href="<%- serverURL %>/auth/saml" class="btn btn-lg btn-block btn-social btn-success"> <i class="fa fa-users"></i> <%= __('Sign in via %s', 'SAML') %> </a> <% } %> - <% if(oauth2) { %> - <a href="<%- url %>/auth/oauth2" class="btn btn-lg btn-block btn-social btn-soundcloud"> - <i class="fa fa-mail-forward"></i> <%= __('Sign in via %s', oauth2ProviderName || 'OAuth2') %> + <% if (authProviders.oauth2) { %> + <a href="<%- serverURL %>/auth/oauth2" class="btn btn-lg btn-block btn-social btn-soundcloud"> + <i class="fa fa-mail-forward"></i> <%= __('Sign in via %s', authProviders.oauth2ProviderName || 'OAuth2') %> </a> <% } %> - <% if((facebook || twitter || github || gitlab || mattermost || dropbox || google || saml || oauth2) && ldap) { %> + <% if ((authProviders.facebook || authProviders.twitter || authProviders.github || authProviders.gitlab || authProviders.mattermost || authProviders.dropbox || authProviders.google || authProviders.saml || authProviders.oauth2) && authProviders.ldap) { %> <hr> <% }%> - <% if(ldap) { %> - <h4>Via <% if (ldapProviderName) { %> <%= ldapProviderName %> (LDAP) <% } else { %> LDAP <% } %></h4> + <% if (authProviders.ldap) { %> + <h4>Via <% if (authProviders.ldapProviderName) { %> <%= authProviders.ldapProviderName %> (LDAP) <% } else { %> LDAP <% } %></h4> <form data-toggle="validator" role="form" class="form-horizontal" method="post" enctype="application/x-www-form-urlencoded"> <div class="form-group"> <div class="col-sm-12"> @@ -73,15 +73,15 @@ </div> <div class="form-group"> <div class="col-sm-12"> - <button type="submit" class="btn btn-primary" formaction="<%- url %>/auth/ldap">Sign in</button> + <button type="submit" class="btn btn-primary" formaction="<%- serverURL %>/auth/ldap">Sign in</button> </div> </div> </form> <% } %> - <% if((facebook || twitter || github || gitlab || mattermost || dropbox || google || ldap || oauth2) && openID) { %> + <% if ((authProviders.facebook || authProviders.twitter || authProviders.github || authProviders.gitlab || authProviders.mattermost || authProviders.dropbox || authProviders.google || authProviders.ldap || authProviders.oauth2) && authProviders.openID) { %> <hr> <% }%> - <% if(openID) { %> + <% if (authProviders.openID) { %> <h4>OpenID</h4> <form data-toggle="validator" role="form" class="form-horizontal" method="post" enctype="application/x-www-form-urlencoded"> <div class="form-group"> @@ -92,15 +92,15 @@ </div> <div class="form-group"> <div class="col-sm-12"> - <button type="submit" class="btn btn-primary" formaction="<%- url %>/auth/openid">Sign in</button> + <button type="submit" class="btn btn-primary" formaction="<%- serverURL %>/auth/openid">Sign in</button> </div> </div> </form> <% } %> - <% if((facebook || twitter || github || gitlab || mattermost || dropbox || google || ldap || oauth2 || openID) && email) { %> + <% if ((authProviders.facebook || authProviders.twitter || authProviders.github || authProviders.gitlab || authProviders.mattermost || authProviders.dropbox || authProviders.google || authProviders.ldap || authProviders.oauth2 || authProviders.openID) && authProviders.email) { %> <hr> <% }%> - <% if(email) { %> + <% if (authProviders.email) { %> <h4>Via Email</h4> <form data-toggle="validator" role="form" class="form-horizontal" method="post" enctype="application/x-www-form-urlencoded"> <div class="form-group"> @@ -117,8 +117,8 @@ </div> <div class="form-group"> <div class="col-sm-12"> - <button type="submit" class="btn btn-primary" formaction="<%- url %>/login">Sign in</button> - <% if(allowEmailRegister) { %><button type="submit" class="btn btn-default" formaction="<%- url %>/register">Register</button><% }%> + <button type="submit" class="btn btn-primary" formaction="<%- serverURL %>/login">Sign in</button> + <% if (authProviders.allowEmailRegister) { %><button type="submit" class="btn btn-default" formaction="<%- serverURL %>/register">Register</button><% }%> </div> </div> </form> diff --git a/public/views/slide.ejs b/public/views/slide.ejs index 42fb5199..9b19af2a 100644 --- a/public/views/slide.ejs +++ b/public/views/slide.ejs @@ -12,8 +12,8 @@ <meta name="description" content="<%= description %>"> <% } %> <title><%= title %></title> - <link rel="icon" type="image/png" href="<%- url %>/favicon.png"> - <link rel="apple-touch-icon" href="<%- url %>/apple-touch-icon.png"> + <link rel="icon" type="image/png" href="<%- serverURL %>/favicon.png"> + <link rel="apple-touch-icon" href="<%- serverURL %>/apple-touch-icon.png"> <% if(useCDN) { %> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fork-awesome/1.1.3/css/fork-awesome.min.css" integrity="sha256-ZhApazu+kejqTYhMF+1DzNKjIzP7KXu6AzyXcC1gMus=" crossorigin="anonymous" /> @@ -23,28 +23,28 @@ <%- include build/slide-header %> <%- include shared/polyfill %> <% } else { %> - <link rel="stylesheet" href="<%- url %>/build/reveal.js/css/reveal.css"> - <link rel="stylesheet" href='<%- url %>/build/emojify.js/dist/css/basic/emojify.min.css'> + <link rel="stylesheet" href="<%- serverURL %>/build/reveal.js/css/reveal.css"> + <link rel="stylesheet" href='<%- serverURL %>/build/emojify.js/dist/css/basic/emojify.min.css'> <%- include build/slide-pack-header %> <% } %> <!-- For reveal.js theme --> <% if(typeof theme !== 'undefined' && theme) { %> - <link rel="stylesheet" href="<%- url %>/build/reveal.js/css/theme/<%= theme %>.css" id="theme"> + <link rel="stylesheet" href="<%- serverURL %>/build/reveal.js/css/theme/<%= theme %>.css" id="theme"> <% } else { %> - <link rel="stylesheet" href="<%- url %>/build/reveal.js/css/theme/black.css" id="theme"> + <link rel="stylesheet" href="<%- serverURL %>/build/reveal.js/css/theme/black.css" id="theme"> <% } %> <!-- For syntax highlighting --> - <link rel="stylesheet" href="<%- url %>/build/reveal.js/lib/css/zenburn.css"> + <link rel="stylesheet" href="<%- serverURL %>/build/reveal.js/lib/css/zenburn.css"> <!-- For overwrite reveal.js --> - <link rel="stylesheet" href="<%- url %>/css/slide.css"> + <link rel="stylesheet" href="<%- serverURL %>/css/slide.css"> <!-- Printing and PDF exports --> <script nonce="<%= cspNonce %>"> var link = document.createElement( 'link' ); link.rel = 'stylesheet'; link.type = 'text/css'; - link.href = '<%- url %>/build/reveal.js/' + (window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css'); + link.href = '<%- serverURL %>/build/reveal.js/' + (window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css'); document.getElementsByTagName( 'head' )[0].appendChild( link ); </script> </head> @@ -86,7 +86,7 @@ </div> </div> - <script src="<%= url %>/js/mathjax-config-extra.js"></script> + <script src="<%= serverURL %>/js/mathjax-config-extra.js"></script> <% if(useCDN) { %> <script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.6.0/lib/js/head.min.js" integrity="sha256-+09kLhwACKXFPDvqo4xMMvi4+uXFsRZ2uYGbeN1U8sI=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.6.0/js/reveal.min.js" integrity="sha256-ixSKHrWAL2k0mqVSRju9+to2/uZSEK9+kJRfdNBolG8=" crossorigin="anonymous"></script> @@ -106,8 +106,8 @@ <script src="https://cdnjs.cloudflare.com/ajax/libs/abcjs/3.1.1/abcjs_basic-min.js" integrity="sha256-Sq1r2XXWXQoShQKsS0Wrf5r7fRkErd9Fat9vHYeU68s=" crossorigin="anonymous"></script> <%- include build/slide-scripts %> <% } else { %> - <script src="<%- url %>/build/MathJax/MathJax.js" defer></script> - <script src="<%- url %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script> + <script src="<%- serverURL %>/build/MathJax/MathJax.js" defer></script> + <script src="<%- serverURL %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script> <%- include build/slide-pack-scripts %> <% } %> </body> diff --git a/tmp/.keep b/tmp/.keep deleted file mode 100644 index e69de29b..00000000 --- a/tmp/.keep +++ /dev/null diff --git a/webpack.common.js b/webpack.common.js index 1fbf247d..1e9c0707 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -202,7 +202,6 @@ module.exports = { 'babel-polyfill', 'script-loader!jquery-ui-resizable', 'script-loader!js-url', - 'expose-loader?filterXSS!xss', 'script-loader!Idle.Js', 'expose-loader?LZString!lz-string', 'script-loader!codemirror', @@ -253,7 +252,6 @@ module.exports = { 'script-loader!handlebars', 'expose-loader?hljs!highlight.js', 'expose-loader?emojify!emojify.js', - 'expose-loader?filterXSS!xss', 'script-loader!Idle.Js', 'script-loader!gist-embed', 'expose-loader?LZString!lz-string', @@ -273,7 +271,6 @@ module.exports = { ], pretty: [ 'babel-polyfill', - 'expose-loader?filterXSS!xss', 'flowchart.js', 'js-sequence-diagrams', 'expose-loader?RevealMarkdown!reveal-markdown', @@ -298,7 +295,6 @@ module.exports = { 'script-loader!handlebars', 'expose-loader?hljs!highlight.js', 'expose-loader?emojify!emojify.js', - 'expose-loader?filterXSS!xss', 'script-loader!gist-embed', 'flowchart.js', 'js-sequence-diagrams', @@ -310,7 +306,6 @@ module.exports = { slide: [ 'babel-polyfill', 'bootstrap-tooltip', - 'expose-loader?filterXSS!xss', 'flowchart.js', 'js-sequence-diagrams', 'expose-loader?RevealMarkdown!reveal-markdown', @@ -338,7 +333,6 @@ module.exports = { 'script-loader!handlebars', 'expose-loader?hljs!highlight.js', 'expose-loader?emojify!emojify.js', - 'expose-loader?filterXSS!xss', 'script-loader!gist-embed', 'flowchart.js', 'js-sequence-diagrams', @@ -716,10 +716,10 @@ autolinker@~0.15.0: resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832" integrity sha1-NCQX2PLzRhsUzwkIjV7fh5HcmDI= -aws-sdk@^2.7.20: - version "2.266.1" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.266.1.tgz#1d0f14cbf82c95cec97752cd5b00df0315a67ff4" - integrity sha512-b8lisloCETh0Fx0il540i+Hbgf3hyegQ6ezoJFggfc1HIbqzvIjVJYJhOsYl1fL1o+iMUaVU4ZH8cSyoMFR2Tw== +aws-sdk@^2.345.0: + version "2.353.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.353.0.tgz#3c809d2b02834d892a3f5c3f1171273b336e5692" + integrity sha512-c5MwJhfcHwA2lC1Wq9csQvP9gz8dVGpZ64s5j9f/sWY6eZiDCQ6OWjxj+VJfpnCmfxyC/pdZO7JDGwems7dqIQ== dependencies: buffer "4.9.1" events "1.1.1" @@ -729,7 +729,7 @@ aws-sdk@^2.7.20: sax "1.2.1" url "0.10.3" uuid "3.1.0" - xml2js "0.4.17" + xml2js "0.4.19" aws-sign2@~0.6.0: version "0.6.0" @@ -7883,11 +7883,12 @@ passport-oauth@^1.0.0: passport-oauth1 "1.x.x" passport-oauth2 "1.x.x" -passport-saml@^0.31.0: - version "0.31.0" - resolved "https://registry.yarnpkg.com/passport-saml/-/passport-saml-0.31.0.tgz#e4d654cab30f018bfd39056efe7bcfa770aab463" - integrity sha1-5NZUyrMPAYv9OQVu/nvPp3CqtGM= +passport-saml@^0.35.0: + version "0.35.0" + resolved "https://registry.yarnpkg.com/passport-saml/-/passport-saml-0.35.0.tgz#06a4952bde9e003923e80efa5c6faffcf7d4f7e0" + integrity sha512-WvLhFeMhAy9GaJvuORR2M6NiW0L9KxSlQRbiTajHBJRMziJ/Yg7uZosrwpoDwhztYaB8PpG0tCuMRG43WWYoCQ== dependencies: + debug "^3.1.0" passport-strategy "*" q "^1.5.0" xml-crypto "^0.10.1" @@ -9184,7 +9185,7 @@ request@2.x, request@^2.40.0, request@^2.79.0, request@^2.81.0, request@^2.86.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@^2.61.0: +request@^2.61.0, request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== @@ -11402,15 +11403,7 @@ xml2js@0.2.8: dependencies: sax "0.5.x" -xml2js@0.4.17: - version "0.4.17" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" - integrity sha1-F76T6q4/O3eTWceVtBlwWogX6Gg= - dependencies: - sax ">=0.6.0" - xmlbuilder "^4.1.0" - -xml2js@0.4.x, xml2js@^0.4.15: +xml2js@0.4.19, xml2js@0.4.x, xml2js@^0.4.15: version "0.4.19" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== @@ -11428,13 +11421,6 @@ xmlbuilder@0.4.3: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-0.4.3.tgz#c4614ba74e0ad196e609c9272cd9e1ddb28a8a58" integrity sha1-xGFLp04K0ZbmCcknLNnh3bKKilg= -xmlbuilder@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" - integrity sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU= - dependencies: - lodash "^4.0.0" - xmlbuilder@^9.0.4, xmlbuilder@~9.0.1: version "9.0.7" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" |