diff options
37 files changed, 397 insertions, 152 deletions
diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..2c3d6b04 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +lib/ot +public/vendor +public/build diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..b826a37b --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + "root": true, + "extends": "standard", + "env": { + "node": true + }, + "rules": { + // at some point all of these should return to their default "error" state + // but right now, this is not a good choice, because too many places are + // wrong. + "import/first": ["warn"], + "indent": ["warn"], + "no-multiple-empty-lines": ["warn"], + "no-multi-spaces": ["warn"], + "object-curly-spacing": ["warn"], + "one-var": ["warn"], + "quotes": ["warn"], + "semi": ["warn"], + "space-infix-ops": ["warn"] + } +}; @@ -1,8 +1,6 @@ CodiMD === -[![Standard - JavaScript Style Guide][standardjs-image]][standardjs-url] - [![#CodiMD on matrix.org][matrix.org-image]][matrix.org-url] [![build status][travis-image]][travis-url] [![version][github-version-badge]][github-release-page] @@ -179,6 +177,7 @@ There are some config settings you need to change in the files below. | `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) | @@ -260,6 +259,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.* @@ -273,6 +273,7 @@ There are some config settings you need to change in the files below. | `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) | @@ -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 @@ -369,7 +371,5 @@ See more at [http://operational-transformation.github.io/](http://operational-tr [travis-url]: https://travis-ci.org/hackmdio/codimd [github-version-badge]: https://img.shields.io/github/release/hackmdio/codimd.svg [github-release-page]: https://github.com/hackmdio/codimd/releases -[standardjs-image]: https://cdn.rawgit.com/feross/standard/master/badge.svg -[standardjs-url]: https://github.com/feross/standard [poeditor-image]: https://img.shields.io/badge/POEditor-translate-blue.svg [poeditor-url]: https://poeditor.com/join/project/1OpGjF2Jir @@ -53,7 +53,7 @@ if (config.useSSL) { // logger app.use(morgan('combined', { - 'stream': logger + 'stream': logger.stream })) // socket io @@ -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 })) @@ -178,6 +178,7 @@ 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 @@ -199,6 +200,11 @@ app.locals.authProviders = { 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')) app.use(require('./lib/web/auth')) diff --git a/config.json.example b/config.json.example index 16c95509..8965add2 100644 --- a/config.json.example +++ b/config.json.example @@ -6,6 +6,7 @@ } }, "development": { + "loglevel": "debug", "hsts": { "enable": false }, @@ -16,6 +17,7 @@ }, "production": { "domain": "localhost", + "loglevel": "info" "hsts": { "enable": true, "maxAgeSeconds": "31536000", 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..71375b98 100644 --- a/lib/config/default.js +++ b/lib/config/default.js @@ -1,10 +1,13 @@ 'use strict' +const os = require('os') + module.exports = { domain: '', urlPath: '', host: '0.0.0.0', port: 3000, + loglevel: 'info', urlAddPort: false, allowOrigin: ['localhost'], useSSL: false, @@ -39,7 +42,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..4220e54d 100644 --- a/lib/config/environment.js +++ b/lib/config/environment.js @@ -3,11 +3,13 @@ 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, port: toIntegerConfig(process.env.CMD_PORT), path: process.env.CMD_PATH, + loglevel: process.env.CMD_LOGLEVEL, urlAddPort: toBooleanConfig(process.env.CMD_URL_ADDPORT), useSSL: toBooleanConfig(process.env.CMD_USESSL), hsts: { diff --git a/lib/config/index.js b/lib/config/index.js index f8b68e30..c1005b0b 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 || @@ -38,6 +45,12 @@ merge(config, require('./hackmdEnvironment')) merge(config, require('./environment')) merge(config, require('./dockerSecret')) +if (['debug', 'verbose', 'info', 'warn', 'error'].includes(config.loglevel)) { + logger.level = config.loglevel +} else { + logger.error('Selected loglevel %s doesn\'t exist, using default level \'debug\'. Available options: debug, verbose, info, warn, error', config.loglevel) +} + // load LDAP CA if (config.ldap.tlsca) { let ca = config.ldap.tlsca.split(',') @@ -110,6 +123,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/logger.js b/lib/logger.js index f8b3895c..5ef1860a 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -1,23 +1,27 @@ 'use strict' -const winston = require('winston') +const {createLogger, format, transports} = require('winston') -class Logger extends winston.Logger { - // Implement stream.writable.write interface - write (chunk) { - this.info(chunk) - } -} - -module.exports = new Logger({ +const logger = createLogger({ + level: 'debug', + format: format.combine( + format.uncolorize(), + format.timestamp(), + format.align(), + format.splat(), + format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`) + ), transports: [ - new winston.transports.Console({ - level: 'debug', - handleExceptions: true, - json: false, - colorize: false, - timestamp: true + new transports.Console({ + handleExceptions: true }) ], - emitErrs: true, exitOnError: false }) + +logger.stream = { + write: function (message, encoding) { + logger.info(message) + } +} + +module.exports = logger diff --git a/lib/models/index.js b/lib/models/index.js index 0a44ca87..ef70475e 100644 --- a/lib/models/index.js +++ b/lib/models/index.js @@ -25,6 +25,7 @@ if (config.dbURL) { // https://github.com/sequelize/sequelize/issues/6485 function stripNullByte (value) { value = '' + value + // eslint-disable-next-line no-control-regex return value ? value.replace(/\u0000/g, '') : value } sequelize.stripNullByte = stripNullByte diff --git a/lib/models/user.js b/lib/models/user.js index 1bd8c745..2ebf6d06 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -50,7 +50,7 @@ module.exports = function (sequelize, DataTypes) { }, { instanceMethods: { verifyPassword: function (attempt) { - if (scrypt.verifyKdfSync(new Buffer(this.password, 'hex'), attempt)) { + if (scrypt.verifyKdfSync(Buffer.from(this.password, 'hex'), attempt)) { return this } else { return false diff --git a/lib/ot/editor-socketio-server.js b/lib/ot/editor-socketio-server.js index 7b204539..5014ac8d 100755 --- a/lib/ot/editor-socketio-server.js +++ b/lib/ot/editor-socketio-server.js @@ -44,7 +44,7 @@ EditorSocketIOServer.prototype.addClient = function (socket) { socket.origin = 'operation'; self.mayWrite(socket, function (mayWrite) { if (!mayWrite) { - console.log("User doesn't have the right to edit."); + logger.info("User doesn't have the right to edit."); return; } try { @@ -71,14 +71,14 @@ EditorSocketIOServer.prototype.addClient = function (socket) { socket.origin = 'selection'; self.mayWrite(socket, function (mayWrite) { if (!mayWrite) { - console.log("User doesn't have the right to edit."); + logger.info("User doesn't have the right to edit."); return; } self.updateSelection(socket, obj && Selection.fromJSON(obj)); }); }); socket.on('disconnect', function () { - //console.log("Disconnect"); + logger.debug("Disconnect"); socket.leave(self.docId); self.onDisconnect(socket); /* @@ -106,7 +106,7 @@ EditorSocketIOServer.prototype.onOperation = function (socket, revision, operati var clientId = socket.id; var wrappedPrime = this.receiveOperation(revision, wrapped); if(!wrappedPrime) return; - //console.log("new operation: " + JSON.stringify(wrapped)); + logger.debug("new operation: " + JSON.stringify(wrapped)); this.getClient(clientId).selection = wrappedPrime.meta; revision = this.operations.length; socket.emit('ack', revision); @@ -161,4 +161,4 @@ EditorSocketIOServer.prototype.onDisconnect = function (socket) { socket.broadcast.to(this.docId).emit('client_left', clientId); }; -module.exports = EditorSocketIOServer;
\ No newline at end of file +module.exports = EditorSocketIOServer; diff --git a/lib/realtime.js b/lib/realtime.js index f6c62d4e..d04ffdc2 100644 --- a/lib/realtime.js +++ b/lib/realtime.js @@ -242,6 +242,7 @@ function getStatus (callback) { } }) models.User.count().then(function (regcount) { + // eslint-disable-next-line standard/no-callback-literal return callback ? callback({ onlineNotes: Object.keys(notes).length, onlineUsers: Object.keys(users).length, @@ -283,7 +284,7 @@ function extractNoteIdFromSocket (socket) { if (!referer) { return false } - var hostUrl = url.parse(referer) + var hostUrl = url.URL.parse(referer) var noteId = config.urlPath ? hostUrl.pathname.slice(config.urlPath.length + 1, hostUrl.pathname.length).split('/')[1] : hostUrl.pathname.split('/')[1] return noteId } else { @@ -887,7 +888,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 3cbd3203..671aa120 100644 --- a/lib/response.js +++ b/lib/response.js @@ -423,6 +423,9 @@ function publishNoteActions (req, res, next) { findNote(req, res, function (note) { var action = req.params.action switch (action) { + case 'download': + actionDownload(req, res, note) + break case 'edit': res.redirect(config.serverURL + '/' + (note.alias ? note.alias : models.Note.encodeNoteId(note.id))) break diff --git a/lib/web/auth/oauth2/index.js b/lib/web/auth/oauth2/index.js index f2a3132d..b9160f6e 100644 --- a/lib/web/auth/oauth2/index.js +++ b/lib/web/auth/oauth2/index.js @@ -2,13 +2,13 @@ const Router = require('express').Router const passport = require('passport') -const OAuth2Strategy = require('passport-oauth2').Strategy +const { Strategy, InternalOAuthError } = require('passport-oauth2') const config = require('../../../config') const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') let oauth2Auth = module.exports = Router() -class OAuth2CustomStrategy extends OAuth2Strategy { +class OAuth2CustomStrategy extends Strategy { constructor (options, verify) { options.customHeaders = options.customHeaders || {} super(options, verify) @@ -22,7 +22,7 @@ class OAuth2CustomStrategy extends OAuth2Strategy { var json if (err) { - return done(new passport.InternalOAuthError('Failed to fetch user profile', err)) + return done(new InternalOAuthError('Failed to fetch user profile', err)) } try { @@ -67,7 +67,7 @@ OAuth2CustomStrategy.prototype.userProfile = function (accessToken, done) { var json if (err) { - return done(new passport.InternalOAuthError('Failed to fetch user profile', err)) + return done(new InternalOAuthError('Failed to fetch user profile', err)) } try { diff --git a/lib/web/imageRouter/filesystem.js b/lib/web/imageRouter/filesystem.js index 8c432b0c..a2f8700d 100644 --- a/lib/web/imageRouter/filesystem.js +++ b/lib/web/imageRouter/filesystem.js @@ -16,5 +16,5 @@ exports.uploadImage = function (imagePath, callback) { return } - callback(null, url.resolve(config.serverURL + '/uploads/', path.basename(imagePath))) + callback(null, url.URL.resolve(config.serverURL + '/uploads/', path.basename(imagePath))) } 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/package.json b/package.json index 524f87e9..bba1e36f 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,10 @@ "main": "app.js", "license": "AGPL-3.0", "scripts": { - "test": "npm run-script standard && npm run-script jsonlint", + "test": "npm run-script eslint && npm run-script jsonlint", + "eslint": "node_modules/.bin/eslint lib public app.js", "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": "node ./node_modules/standard/bin/cmd.js", + "standard": "echo 'standard is no longer being used, use `npm run eslint` instead!' && exit 1", "dev": "webpack --config webpack.dev.js --progress --colors --watch", "build": "webpack --config webpack.prod.js --progress --colors --bail", "postinstall": "bin/heroku", @@ -19,7 +20,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 +63,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 +99,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 +109,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", @@ -129,7 +130,7 @@ "velocity-animate": "^1.4.0", "visibilityjs": "^1.2.4", "viz.js": "^1.7.0", - "winston": "^2.3.0", + "winston": "^3.1.0", "ws": "^6.0.0", "xss": "^1.0.3" }, @@ -169,6 +170,12 @@ "css-loader": "^1.0.0", "doctoc": "^1.3.0", "ejs-loader": "^0.3.1", + "eslint": "^5.9.0", + "eslint-config-standard": "^12.0.0", + "eslint-plugin-import": "^2.14.0", + "eslint-plugin-node": "^8.0.0", + "eslint-plugin-promise": "^4.0.1", + "eslint-plugin-standard": "^4.0.0", "exports-loader": "^0.7.0", "expose-loader": "^0.7.5", "file-loader": "^2.0.0", @@ -180,7 +187,6 @@ "mini-css-extract-plugin": "^0.4.1", "optimize-css-assets-webpack-plugin": "^5.0.0", "script-loader": "^0.7.2", - "standard": "^9.0.1", "string-loader": "^0.0.1", "style-loader": "^0.21.0", "uglifyjs-webpack-plugin": "^1.2.7", @@ -190,34 +196,6 @@ "webpack-merge": "^4.1.4", "webpack-parallel-uglify-plugin": "^1.1.0" }, - "standard": { - "globals": [ - "$", - "CodeMirror", - "Cookies", - "moment", - "editor", - "ui", - "Spinner", - "modeType", - "Idle", - "serverurl", - "key", - "gapi", - "Dropbox", - "FilePicker", - "ot", - "MediaUploader", - "hex2rgb", - "num_loaded", - "Visibility", - "inlineAttachment" - ], - "ignore": [ - "lib/ot", - "public/vendor" - ] - }, "optionalDependencies": { "bufferutil": "^4.0.0", "utf-8-validate": "^5.0.1" diff --git a/public/.eslintrc.js b/public/.eslintrc.js new file mode 100644 index 00000000..dc37b3cb --- /dev/null +++ b/public/.eslintrc.js @@ -0,0 +1,28 @@ +// this config file is used in concert with the root .eslintrc.js in the root dir. +module.exports = { + "env": { + "browser": true + }, + "globals": { + "$": false, + "CodeMirror": false, + "Cookies": false, + "moment": false, + "editor": false, + "ui": false, + "Spinner": false, + "modeType": false, + "Idle": false, + "serverurl": false, + "key": false, + "gapi": false, + "Dropbox": false, + "FilePicker": false, + "ot": false, + "MediaUploader": false, + "hex2rgb": false, + "num_loaded": false, + "Visibility": false, + "inlineAttachment": false + } +}; diff --git a/public/docs/features.md b/public/docs/features.md index 3d790039..a4ffb633 100644 --- a/public/docs/features.md +++ b/public/docs/features.md @@ -72,9 +72,11 @@ Notes can be embedded as follows: ## [Slide Mode](./slide-example): You can use a special syntax to organize your note into slides. -After that, you can use the **Slide Mode** <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. +To switch the editor into slide mode, set the [document type](./yaml-metadata#type) to `slide`. + View === ## Table of Contents: @@ -88,9 +90,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/docs/slide-example.md b/public/docs/slide-example.md index 5503cbd7..49503669 100644 --- a/public/docs/slide-example.md +++ b/public/docs/slide-example.md @@ -1,4 +1,5 @@ --- +type: slide slideOptions: transition: slide --- diff --git a/public/docs/yaml-metadata.md b/public/docs/yaml-metadata.md index 888345f7..839616a8 100644 --- a/public/docs/yaml-metadata.md +++ b/public/docs/yaml-metadata.md @@ -25,7 +25,7 @@ This option will set the note title which prior than content title. > default: not set **Example** -```xml +```yml title: meta title ``` @@ -36,7 +36,7 @@ This option will set the note description. > default: not set **Example** -```xml +```yml description: meta description ``` @@ -47,7 +47,7 @@ This option will set the tags which prior than content tags. > default: not set **Example** -```xml +```yml tags: features, cool, updated ``` @@ -62,7 +62,7 @@ So you can prevent any search engine index your note by set `noindex, nofollow`. > default: not set **Example** -```xml +```yml robots: noindex, nofollow ``` @@ -75,13 +75,13 @@ https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes > default: not set (which will be en) **Example** -```xml +```yml langs: ja-jp ``` dir --- -This option provide to describe the direction of the text in this note. +This option specifies the direction of the text in this note. You can only use whether `rtl` or `ltr`. Look more at here: http://www.w3.org/International/questions/qa-html-dir @@ -89,7 +89,7 @@ http://www.w3.org/International/questions/qa-html-dir > default: not set (which will be ltr) **Example** -```xml +```yml dir: rtl ``` @@ -102,35 +102,46 @@ You can only use whether `true` or `false`. > default: not set (which will be true) **Example** -```xml +```yml breaks: false ``` GA --- -This option allow you to enable Google Analytics with your ID. +This option allows you to enable Google Analytics with your ID. > default: not set (which won't enable) **Example** -```xml +```yml GA: UA-12345667-8 ``` disqus --- -This option allow you to enable Disqus with your shortname. +This option allows you to enable Disqus with your shortname. > default: not set (which won't enable) **Example** -```xml +```yml disqus: codimd ``` +type +--- +This option allows you to switch the document view to the slide preview, to simplify live editing of presentations. + +> default: not set + +**Example:** +```yml +type: slide +``` + slideOptions --- -This option allow you provide custom options to slide mode. +This option allows you to provide custom options to slide mode. Please below document for more details: https://github.com/hakimel/reveal.js/#configuration @@ -142,7 +153,7 @@ https://github.com/hakimel/reveal.js/tree/master/css/theme > default: not set (which use default slide options) **Example** -```xml +```yml slideOptions: transition: fade theme: white diff --git a/public/js/extra.js b/public/js/extra.js index 4db36ff6..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: - /:([^\s:]+):/, + // 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/history.js b/public/js/history.js index b4c26b42..6007bef4 100644 --- a/public/js/history.js +++ b/public/js/history.js @@ -218,6 +218,7 @@ export function getStorageHistory (callback) { if (typeof data === 'string') { data = JSON.parse(data) } callback(data) } + // eslint-disable-next-line standard/no-callback-literal callback([]) } diff --git a/public/js/index.js b/public/js/index.js index 98c3b6d2..0c575961 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -2511,7 +2511,9 @@ function buildCursor (user) { // editor actions function removeNullByte (cm, change) { var str = change.text.join('\n') + // eslint-disable-next-line no-control-regex if (/\u0000/g.test(str) && change.update) { + // eslint-disable-next-line no-control-regex change.update(change.from, change.to, str.replace(/\u0000/g, '').split('\n')) } } @@ -3046,7 +3048,7 @@ function checkInCode () { function checkAbove (method) { var cursor = editor.getCursor() var text = [] - for (var i = 0; i < cursor.line; i++) { // contain current line + for (var i = 0; i < cursor.line; i++) { // contain current line text.push(editor.getLine(i)) } text = text.join('\n') + '\n' + editor.getLine(cursor.line).slice(0, cursor.ch) diff --git a/public/js/lib/editor/index.js b/public/js/lib/editor/index.js index 0537e927..f05d01b8 100644 --- a/public/js/lib/editor/index.js +++ b/public/js/lib/editor/index.js @@ -492,7 +492,7 @@ export default class Editor { clearInterval(spellcheckTimer) } }, - 100, + 100 ) } } @@ -514,7 +514,7 @@ export default class Editor { } setOverrideBrowserKeymap () { var overrideBrowserKeymap = $( - '.ui-preferences-override-browser-keymap label > input[type="checkbox"]', + '.ui-preferences-override-browser-keymap label > input[type="checkbox"]' ) if (overrideBrowserKeymap.is(':checked')) { Cookies.set('preferences-override-browser-keymap', true, { @@ -529,10 +529,10 @@ export default class Editor { setPreferences () { var overrideBrowserKeymap = $( - '.ui-preferences-override-browser-keymap label > input[type="checkbox"]', + '.ui-preferences-override-browser-keymap label > input[type="checkbox"]' ) var cookieOverrideBrowserKeymap = Cookies.get( - 'preferences-override-browser-keymap', + 'preferences-override-browser-keymap' ) if (cookieOverrideBrowserKeymap && cookieOverrideBrowserKeymap === 'true') { overrideBrowserKeymap.prop('checked', true) diff --git a/public/js/lib/editor/ui-elements.js b/public/js/lib/editor/ui-elements.js index ca06d30c..29a37782 100644 --- a/public/js/lib/editor/ui-elements.js +++ b/public/js/lib/editor/ui-elements.js @@ -67,7 +67,7 @@ export const getUIElements = () => ({ codemirrorScroll: $('.ui-edit-area .CodeMirror .CodeMirror-scroll'), codemirrorSizer: $('.ui-edit-area .CodeMirror .CodeMirror-sizer'), codemirrorSizerInner: $( - '.ui-edit-area .CodeMirror .CodeMirror-sizer > div', + '.ui-edit-area .CodeMirror .CodeMirror-sizer > div' ), markdown: $('.ui-view-area .markdown-body'), resize: { 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/header.ejs b/public/views/codimd/header.ejs index d8df33b8..b83838ea 100644 --- a/public/views/codimd/header.ejs +++ b/public/views/codimd/header.ejs @@ -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> <% } %> @@ -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/index/body.ejs b/public/views/index/body.ejs index 907cc1a8..43582d78 100644 --- a/public/views/index/body.ejs +++ b/public/views/index/body.ejs @@ -150,7 +150,7 @@ <option value="id">Bahasa Indonesia</option> </select> <p> - Powered by <a href="https://codimd.org">CodiMD</a> | <a href="<%- serverURL %>/s/release-notes" target="_blank" rel="noopener"><%= __('Releases') %></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 <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>') %> 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" |