diff --git a/client/build/components/AssetShareButtons/index.js b/client/build/components/AssetShareButtons/index.js new file mode 100644 index 00000000..8b54ec2b --- /dev/null +++ b/client/build/components/AssetShareButtons/index.js @@ -0,0 +1,38 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _react = _interopRequireDefault(require("react")); + +var _SpaceBetween = _interopRequireDefault(require("@components/SpaceBetween")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var AssetShareButtons = function AssetShareButtons(_ref) { + var host = _ref.host, + name = _ref.name, + shortId = _ref.shortId; + return _react.default.createElement(_SpaceBetween.default, null, _react.default.createElement("a", { + className: "link--primary", + target: "_blank", + href: "https://twitter.com/intent/tweet?text=".concat(host, "/").concat(shortId, "/").concat(name) + }, "twitter"), _react.default.createElement("a", { + className: "link--primary", + target: "_blank", + href: "https://www.facebook.com/sharer/sharer.php?u=".concat(host, "/").concat(shortId, "/").concat(name) + }, "facebook"), _react.default.createElement("a", { + className: "link--primary", + target: "_blank", + href: "http://tumblr.com/widgets/share/tool?canonicalUrl=".concat(host, "/").concat(shortId, "/").concat(name) + }, "tumblr"), _react.default.createElement("a", { + className: "link--primary", + target: "_blank", + href: "https://www.reddit.com/submit?url=".concat(host, "/").concat(shortId, "/").concat(name, "&title=").concat(name) + }, "reddit")); +}; + +var _default = AssetShareButtons; +exports.default = _default; \ No newline at end of file diff --git a/client/build/components/ClickToCopy/index.js b/client/build/components/ClickToCopy/index.js new file mode 100644 index 00000000..0c0b93e5 --- /dev/null +++ b/client/build/components/ClickToCopy/index.js @@ -0,0 +1,82 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _react = _interopRequireDefault(require("react")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } _setPrototypeOf(subClass.prototype, superClass && superClass.prototype); if (superClass) _setPrototypeOf(subClass, superClass); } + +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } + +function _getPrototypeOf(o) { _getPrototypeOf = Object.getPrototypeOf || function _getPrototypeOf(o) { return o.__proto__; }; return _getPrototypeOf(o); } + +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } + +var ClickToCopy = +/*#__PURE__*/ +function (_React$Component) { + function ClickToCopy(props) { + var _this; + + _classCallCheck(this, ClickToCopy); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(ClickToCopy).call(this, props)); + _this.copyToClipboard = _this.copyToClipboard.bind(_assertThisInitialized(_assertThisInitialized(_this))); + return _this; + } + + _createClass(ClickToCopy, [{ + key: "copyToClipboard", + value: function copyToClipboard(event) { + var elementToCopy = event.target.id; + var element = document.getElementById(elementToCopy); + element.select(); + + try { + document.execCommand('copy'); + } catch (err) { + this.setState({ + error: 'Oops, unable to copy' + }); + } + } + }, { + key: "render", + value: function render() { + var _this$props = this.props, + id = _this$props.id, + value = _this$props.value; + return _react.default.createElement("input", { + id: id, + value: value, + onClick: this.copyToClipboard, + type: "text", + className: "click-to-copy", + readOnly: true, + spellCheck: "false" + }); + } + }]); + + _inherits(ClickToCopy, _React$Component); + + return ClickToCopy; +}(_react.default.Component); + +var _default = ClickToCopy; +exports.default = _default; \ No newline at end of file diff --git a/client/build/containers/AssetInfo/view.js b/client/build/containers/AssetInfo/view.js index a405af12..55eefee1 100644 --- a/client/build/containers/AssetInfo/view.js +++ b/client/build/containers/AssetInfo/view.js @@ -17,6 +17,10 @@ var _Row = _interopRequireDefault(require("@components/Row")); var _SpaceBetween = _interopRequireDefault(require("@components/SpaceBetween")); +var _AssetShareButtons = _interopRequireDefault(require("@components/AssetShareButtons")); + +var _ClickToCopy = _interopRequireDefault(require("@components/ClickToCopy")); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } @@ -33,80 +37,20 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } -function _getPrototypeOf(o) { _getPrototypeOf = Object.getPrototypeOf || function _getPrototypeOf(o) { return o.__proto__; }; return _getPrototypeOf(o); } - function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } -var AssetShareButtons = function AssetShareButtons(_ref) { - var host = _ref.host, - name = _ref.name, - shortId = _ref.shortId; - return _react.default.createElement(_SpaceBetween.default, null, _react.default.createElement("a", { - className: "link--primary", - target: "_blank", - href: "https://twitter.com/intent/tweet?text=".concat(host, "/").concat(shortId, "/").concat(name) - }, "twitter"), _react.default.createElement("a", { - className: "link--primary", - target: "_blank", - href: "https://www.facebook.com/sharer/sharer.php?u=".concat(host, "/").concat(shortId, "/").concat(name) - }, "facebook"), _react.default.createElement("a", { - className: "link--primary", - target: "_blank", - href: "http://tumblr.com/widgets/share/tool?canonicalUrl=".concat(host, "/").concat(shortId, "/").concat(name) - }, "tumblr"), _react.default.createElement("a", { - className: "link--primary", - target: "_blank", - href: "https://www.reddit.com/submit?url=".concat(host, "/").concat(shortId, "/").concat(name, "&title=").concat(name) - }, "reddit")); -}; - -var ClickToCopy = function ClickToCopy(_ref2) { - var id = _ref2.id, - value = _ref2.value, - copyToClipboard = _ref2.copyToClipboard; - return _react.default.createElement("input", { - id: id, - value: value, - onClick: copyToClipboard, - type: "text", - className: "click-to-copy", - readOnly: true, - spellCheck: "false" - }); -}; +function _getPrototypeOf(o) { _getPrototypeOf = Object.getPrototypeOf || function _getPrototypeOf(o) { return o.__proto__; }; return _getPrototypeOf(o); } var AssetInfo = /*#__PURE__*/ function (_React$Component) { - function AssetInfo(props) { - var _this; - + function AssetInfo() { _classCallCheck(this, AssetInfo); - _this = _possibleConstructorReturn(this, _getPrototypeOf(AssetInfo).call(this, props)); - _this.copyToClipboard = _this.copyToClipboard.bind(_assertThisInitialized(_assertThisInitialized(_this))); - return _this; + return _possibleConstructorReturn(this, _getPrototypeOf(AssetInfo).apply(this, arguments)); } _createClass(AssetInfo, [{ - key: "copyToClipboard", - value: function copyToClipboard(event) { - console.log('event:', event); - console.log('event.target:', event.target); - console.log('event.target.id:', event.target.id); - var elementToCopy = event.target.id; - var element = document.getElementById(elementToCopy); - element.select(); - - try { - document.execCommand('copy'); - } catch (err) { - this.setState({ - error: 'Oops, unable to copy' - }); - } - } - }, { key: "render", value: function render() { var _this$props$asset = this.props.asset, @@ -134,31 +78,29 @@ function (_React$Component) { label: _react.default.createElement(_Label.default, { value: 'Share:' }), - content: _react.default.createElement(AssetShareButtons, { + content: _react.default.createElement(_AssetShareButtons.default, { host: host, + name: name, shortId: shortId }) })), _react.default.createElement(_Row.default, null, _react.default.createElement(_RowLabeled.default, { label: _react.default.createElement(_Label.default, { value: 'Link:' }), - content: _react.default.createElement(ClickToCopy, { + content: _react.default.createElement(_ClickToCopy.default, { id: 'short-link', - value: "".concat(host, "/").concat(shortId, "/").concat(name, ".").concat(fileExt), - copyToClipboard: this.copyToClipboard + value: "".concat(host, "/").concat(shortId, "/").concat(name, ".").concat(fileExt) }) })), _react.default.createElement(_Row.default, null, _react.default.createElement(_RowLabeled.default, { label: _react.default.createElement(_Label.default, { value: 'Embed:' }), - content: _react.default.createElement("div", null, contentType === 'video/mp4' ? _react.default.createElement(ClickToCopy, { + content: _react.default.createElement("div", null, contentType === 'video/mp4' ? _react.default.createElement(_ClickToCopy.default, { id: 'embed-text-video', - value: ""), - copyToClipboard: this.copyToClipboard - }) : _react.default.createElement(ClickToCopy, { + value: "") + }) : _react.default.createElement(_ClickToCopy.default, { id: 'embed-text-image', - value: ""), - copyToClipboard: this.copyToClipboard + value: "") })) })), _react.default.createElement(_Row.default, null, _react.default.createElement(_SpaceBetween.default, null, _react.default.createElement(_reactRouterDom.Link, { className: "link--primary", diff --git a/client/build/containers/PublishDisabledMessage/view.js b/client/build/containers/PublishDisabledMessage/view.js index 24487939..7ef8f198 100644 --- a/client/build/containers/PublishDisabledMessage/view.js +++ b/client/build/containers/PublishDisabledMessage/view.js @@ -40,11 +40,15 @@ function (_React$Component) { key: "render", value: function render() { var message = this.props.message; - return _react.default.createElement("div", null, _react.default.createElement("p", { + return _react.default.createElement("div", { + className: 'publish-disabled-message' + }, _react.default.createElement("div", { + className: 'message' + }, _react.default.createElement("p", { className: 'text--secondary' }, "Publishing is currently disabled."), _react.default.createElement("p", { className: 'text--secondary' - }, message)); + }, message))); } }]); diff --git a/client/build/utils/metaTags.js b/client/build/utils/metaTags.js index 34daa9e0..9713f663 100644 --- a/client/build/utils/metaTags.js +++ b/client/build/utils/metaTags.js @@ -101,9 +101,9 @@ var createAssetMetaTags = function createAssetMetaTags(_ref3) { defaultThumbnail = _ref3.defaultThumbnail; var claimData = asset.claimData; var contentType = claimData.contentType; - var embedUrl = "".concat(siteHost, "/").concat(claimData.claimId, "/").concat(claimData.name); + var videoEmbedUrl = "".concat(siteHost, "/video-embed/").concat(claimData.name, "/").concat(claimData.claimId); var showUrl = "".concat(siteHost, "/").concat(claimData.claimId, "/").concat(claimData.name); - var source = "".concat(siteHost, "/").concat(claimData.claimId, "/").concat(claimData.name, ".").concat(claimData.fileExt); + var source = "".concat(siteHost, "/asset/").concat(claimData.name, "/").concat(claimData.claimId); var ogTitle = claimData.title || claimData.name; var ogDescription = claimData.description || defaultDescription; var ogThumbnailContentType = determineOgThumbnailContentType(claimData.thumbnail); @@ -154,7 +154,7 @@ var createAssetMetaTags = function createAssetMetaTags(_ref3) { }); metaTags.push({ property: 'og:type', - content: 'video' + content: 'video.other' }); metaTags.push({ property: 'twitter:card', @@ -162,7 +162,7 @@ var createAssetMetaTags = function createAssetMetaTags(_ref3) { }); metaTags.push({ property: 'twitter:player', - content: embedUrl + content: videoEmbedUrl }); metaTags.push({ property: 'twitter:player:width', diff --git a/client/scss/all.scss b/client/scss/all.scss index 6675e5c5..e2da3336 100644 --- a/client/scss/all.scss +++ b/client/scss/all.scss @@ -40,6 +40,7 @@ @import 'containers/_dropzone'; @import 'containers/_publish-url-input'; @import 'containers/_publish-status'; +@import 'containers/_publish-disabled-message'; @import '_media-queries'; diff --git a/client/scss/containers/_publish-disabled-message.scss b/client/scss/containers/_publish-disabled-message.scss new file mode 100644 index 00000000..66bdba7c --- /dev/null +++ b/client/scss/containers/_publish-disabled-message.scss @@ -0,0 +1,11 @@ +.publish-disabled-message { + // fill the parent flex container + flex: 1 0 auto; + // be a flex container for children + display: flex; + flex-direction: column; + justify-content: center; + .message { + text-align: center; + } +} diff --git a/client/src/components/AssetShareButtons/index.js b/client/src/components/AssetShareButtons/index.js new file mode 100644 index 00000000..dfb0c0b9 --- /dev/null +++ b/client/src/components/AssetShareButtons/index.js @@ -0,0 +1,39 @@ +import React from 'react'; +import SpaceBetween from '@components/SpaceBetween'; + +const AssetShareButtons = ({ host, name, shortId }) => { + return ( + + + twitter + + + facebook + + + tumblr + + + reddit + + + ); +}; + +export default AssetShareButtons; diff --git a/client/src/components/ClickToCopy/index.jsx b/client/src/components/ClickToCopy/index.jsx new file mode 100644 index 00000000..35b7dba8 --- /dev/null +++ b/client/src/components/ClickToCopy/index.jsx @@ -0,0 +1,34 @@ +import React from 'react'; + +class ClickToCopy extends React.Component { + constructor (props) { + super(props); + this.copyToClipboard = this.copyToClipboard.bind(this); + } + copyToClipboard (event) { + const elementToCopy = event.target.id; + const element = document.getElementById(elementToCopy); + element.select(); + try { + document.execCommand('copy'); + } catch (err) { + this.setState({error: 'Oops, unable to copy'}); + } + } + render () { + const {id, value} = this.props; + return ( + + ); + } +} + +export default ClickToCopy; diff --git a/client/src/containers/AssetInfo/view.jsx b/client/src/containers/AssetInfo/view.jsx index 12427c27..e251e81d 100644 --- a/client/src/containers/AssetInfo/view.jsx +++ b/client/src/containers/AssetInfo/view.jsx @@ -4,74 +4,10 @@ import Label from '@components/Label'; import RowLabeled from '@components/RowLabeled'; import Row from '@components/Row'; import SpaceBetween from '@components/SpaceBetween'; - -const AssetShareButtons = ({ host, name, shortId }) => { - return ( - - - twitter - - - facebook - - - tumblr - - - reddit - - - ); -}; - -const ClickToCopy = ({id, value, copyToClipboard}) => { - return ( - - ); -}; +import AssetShareButtons from '@components/AssetShareButtons'; +import ClickToCopy from '@components/ClickToCopy'; class AssetInfo extends React.Component { - constructor (props) { - super(props); - this.copyToClipboard = this.copyToClipboard.bind(this); - } - copyToClipboard (event) { - console.log('event:', event); - console.log('event.target:', event.target); - console.log('event.target.id:', event.target.id); - const elementToCopy = event.target.id; - const element = document.getElementById(elementToCopy); - element.select(); - try { - document.execCommand('copy'); - } catch (err) { - this.setState({error: 'Oops, unable to copy'}); - } - } render () { const { asset: { shortId, claimData : { channelName, certificateId, description, name, claimId, fileExt, contentType, thumbnail, host } } } = this.props; return ( @@ -99,6 +35,7 @@ class AssetInfo extends React.Component { content={ } @@ -114,7 +51,6 @@ class AssetInfo extends React.Component { } /> @@ -131,13 +67,11 @@ class AssetInfo extends React.Component { `} - copyToClipboard={this.copyToClipboard} /> ) : ( `} - copyToClipboard={this.copyToClipboard} /> )} diff --git a/client/src/containers/PublishDisabledMessage/view.jsx b/client/src/containers/PublishDisabledMessage/view.jsx index b48271de..355ce75d 100644 --- a/client/src/containers/PublishDisabledMessage/view.jsx +++ b/client/src/containers/PublishDisabledMessage/view.jsx @@ -4,9 +4,11 @@ class PublishDisabledMessage extends React.Component { render () { const message = this.props.message; return ( -
-

Publishing is currently disabled.

-

{message}

+
+
+

Publishing is currently disabled.

+

{message}

+
); } diff --git a/client/src/utils/metaTags.js b/client/src/utils/metaTags.js index cd11b853..c5b9df34 100644 --- a/client/src/utils/metaTags.js +++ b/client/src/utils/metaTags.js @@ -46,9 +46,9 @@ const createChannelMetaTags = ({siteHost, siteTitle, siteTwitter, channel}) => { const createAssetMetaTags = ({siteHost, siteTitle, siteTwitter, asset, defaultDescription, defaultThumbnail}) => { const { claimData } = asset; const { contentType } = claimData; - const embedUrl = `${siteHost}/${claimData.claimId}/${claimData.name}`; + const videoEmbedUrl = `${siteHost}/video-embed/${claimData.name}/${claimData.claimId}`; const showUrl = `${siteHost}/${claimData.claimId}/${claimData.name}`; - const source = `${siteHost}/${claimData.claimId}/${claimData.name}.${claimData.fileExt}`; + const source = `${siteHost}/asset/${claimData.name}/${claimData.claimId}`; const ogTitle = claimData.title || claimData.name; const ogDescription = claimData.description || defaultDescription; const ogThumbnailContentType = determineOgThumbnailContentType(claimData.thumbnail); @@ -68,9 +68,9 @@ const createAssetMetaTags = ({siteHost, siteTitle, siteTwitter, asset, defaultDe metaTags.push({property: 'og:video:type', content: contentType}); metaTags.push({property: 'og:image', content: ogThumbnail}); metaTags.push({property: 'og:image:type', content: ogThumbnailContentType}); - metaTags.push({property: 'og:type', content: 'video'}); + metaTags.push({property: 'og:type', content: 'video.other'}); metaTags.push({property: 'twitter:card', content: 'player'}); - metaTags.push({property: 'twitter:player', content: embedUrl}); + metaTags.push({property: 'twitter:player', content: videoEmbedUrl}); metaTags.push({property: 'twitter:player:width', content: 600}); metaTags.push({property: 'twitter:text:player_width', content: 600}); metaTags.push({property: 'twitter:player:height', content: 337}); diff --git a/index.js b/index.js index fb4e362e..be30317c 100644 --- a/index.js +++ b/index.js @@ -35,6 +35,10 @@ const speechPassport = require('./server/speechPassport'); const { details: { port: PORT }, auth: { sessionKey }, + startup: { + performChecks, + performUpdates, + }, } = require('@config/siteConfig'); function Server () { @@ -97,31 +101,70 @@ function Server () { /* create server */ this.server = http.Server(this.app); }; + this.startServerListening = () => { + logger.info(`Starting server on ${PORT}...`); + return new Promise((resolve, reject) => { + this.server.listen(PORT, () => { + logger.info(`Server is listening on PORT ${PORT}`); + resolve(); + }) + }); + }; this.syncDatabase = () => { + logger.info(`Syncing database...`); return createDatabaseIfNotExists() .then(() => { db.sequelize.sync(); }) }; + this.performChecks = () => { + if (!performChecks) { + return; + } + logger.info(`Performing checks...`); + return Promise.all([ + getWalletBalance(), + ]) + .then(([walletBalance]) => { + logger.info('Starting LBC balance:', walletBalance); + }) + }; + this.performUpdates = () => { + if (!performUpdates) { + return; + } + logger.info(`Peforming updates...`); + return Promise.all([ + db.Blocked.refreshTable(), + db.Tor.refreshTable(), + ]) + .then(([updatedBlockedList, updatedTorList]) => { + logger.info('Blocked list updated, length:', updatedBlockedList.length); + logger.info('Tor list updated, length:', updatedTorList.length); + }) + }; this.start = () => { this.initialize(); this.createApp(); this.createServer(); - /* start the server */ - logger.info('getting LBC balance & syncing database...'); - Promise.all([ - this.syncDatabase(), - getWalletBalance(), - ]) - .then(([syncResult, walletBalance]) => { - logger.info('starting LBC balance:', walletBalance); - return this.server.listen(PORT, () => { - logger.info(`Server is listening on PORT ${PORT}`); - }) + this.syncDatabase() + .then(() => { + return this.startServerListening(); + }) + .then(() => { + return Promise.all([ + this.performChecks(), + this.performUpdates(), + ]) + }) + .then(() => { + logger.info('Spee.ch startup is complete'); }) .catch(error => { if (error.code === 'ECONNREFUSED') { return logger.error('Connection refused. The daemon may not be running.') + } else if (error.code === 'EADDRINUSE') { + return logger.error('Server could not start listening. The port is already in use.'); } else if (error.message) { logger.error(error.message); } diff --git a/server/controllers/api/blocked/index.js b/server/controllers/api/blocked/index.js new file mode 100644 index 00000000..aad2dfc2 --- /dev/null +++ b/server/controllers/api/blocked/index.js @@ -0,0 +1,22 @@ +const logger = require('winston'); +const db = require('../../../models'); + +const updateBlockedList = (req, res) => { + db.Blocked.refreshTable() + .then(data => { + logger.info('finished updating blocked content list'); + res.status(200).json({ + success: true, + data, + }); + }) + .catch(error => { + logger.error(error); + res.status(500).json({ + success: false, + error, + }); + }); +}; + +module.exports = updateBlockedList; diff --git a/server/controllers/api/claim/blockedList/index.js b/server/controllers/api/claim/blockedList/index.js deleted file mode 100644 index abc80d8e..00000000 --- a/server/controllers/api/claim/blockedList/index.js +++ /dev/null @@ -1,56 +0,0 @@ -const logger = require('winston'); -const db = require('../../../../models'); - -const updateBlockedList = (req, res) => { - return fetch('https://api.lbry.io/file/list_blocked') - .then(response => { - return response.json(); - }) - .then(jsonResponse => { - if (!jsonResponse.data) { - throw new Error('no data in list_blocked response'); - } - if (!jsonResponse.data.outpoints) { - throw new Error('no outpoints in list_blocked response'); - } - return jsonResponse.data.outpoints; - }) - .then(outpoints => { - logger.info('number of blocked outpoints:', outpoints.length); - let updatePromises = []; - outpoints.forEach(outpoint => { - // logger.debug('outpoint:', outpoint); - updatePromises.push(db.Claim - .findOne({ - where: { - outpoint, - }, - }) - .then(Claim => { - if (Claim) { - const { claimId, name } = Claim; - logger.debug(`creating record in Blocked for ${name}#${claimId}`); - const blocked = { - claimId, - name, - outpoint, - }; - return db.upsert(db.Blocked, blocked, blocked, 'Blocked') - } - }) - .catch(error => { - logger.error(error); - })); - }); - return Promise.all(updatePromises); - }) - .then(() => { - logger.info('finished updating blocked content list'); - res.status(200).json({success: true, message: 'finished updating blocked content list'}); - }) - .catch((error) => { - logger.error(error); - }); -}; - -module.exports = updateBlockedList; diff --git a/server/controllers/api/claim/longId/index.js b/server/controllers/api/claim/longId/index.js index 0eb3668c..27f66b1c 100644 --- a/server/controllers/api/claim/longId/index.js +++ b/server/controllers/api/claim/longId/index.js @@ -22,7 +22,10 @@ const claimLongId = ({ ip, originalUrl, body, params }, res) => { getClaimId(channelName, channelClaimId, claimName, claimId) .then(fullClaimId => { claimId = fullClaimId; - return db.Blocked.isNotBlocked(fullClaimId, claimName); + return db.Claim.getOutpoint(claimName, fullClaimId); + }) + .then(outpoint => { + return db.Blocked.isNotBlocked(outpoint); }) .then(() => { res.status(200).json({success: true, data: claimId}); diff --git a/server/controllers/api/claim/publish/index.js b/server/controllers/api/claim/publish/index.js index 15e48ee9..b429e797 100644 --- a/server/controllers/api/claim/publish/index.js +++ b/server/controllers/api/claim/publish/index.js @@ -1,4 +1,6 @@ -const { details: { host } } = require('@config/siteConfig'); +const logger = require('winston'); + +const { details: { host }, publishing: { disabled, disabledMessage } } = require('@config/siteConfig'); const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js'); @@ -19,7 +21,20 @@ const authenticateUser = require('./authentication.js'); */ -const claimPublish = ({ body, files, headers, ip, originalUrl, user }, res) => { +const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res) => { + // logging + logger.info('Publish request:', { + ip, + headers, + body, + }); + // check for disabled publishing + if (disabled) { + return res.status(503).json({ + success: false, + message: disabledMessage + }); + } // define variables let channelName, channelId, channelPassword, description, fileName, filePath, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title; // record the start time of the request diff --git a/server/controllers/api/config/site/publishing/index.js b/server/controllers/api/config/site/publishing/index.js new file mode 100644 index 00000000..08e60bf3 --- /dev/null +++ b/server/controllers/api/config/site/publishing/index.js @@ -0,0 +1,29 @@ +const { publishing: { + primaryClaimAddress, + uploadDirectory, + thumbnailChannel, + thumbnailChannelId, + additionalClaimAddresses, + disabled, + disabledMessage +} } = require('@config/siteConfig'); + +/* + + route to see if publishing is enabled + +*/ + +const publishingConfig = (req, res) => { + return res.status(200).json({ + primaryClaimAddress, + uploadDirectory, + thumbnailChannel, + thumbnailChannelId, + additionalClaimAddresses, + disabled, + disabledMessage + }); +}; + +module.exports = publishingConfig; diff --git a/server/controllers/api/tor/index.js b/server/controllers/api/tor/index.js new file mode 100644 index 00000000..df4c5831 --- /dev/null +++ b/server/controllers/api/tor/index.js @@ -0,0 +1,25 @@ +const logger = require('winston'); +const db = require('../../../models'); + +/* + + Route to update and return tor exit nodes that can connect to this ip address + +*/ + +const getTorList = (req, res) => { + db.Tor.refreshTable() + .then( result => { + logger.debug('number of records', result.length); + res.status(200).json(result); + }) + .catch((error) => { + logger.error(error); + res.status(500).json({ + success: false, + error, + }) + }); +}; + +module.exports = getTorList; diff --git a/server/controllers/assets/constants/request_types.js b/server/controllers/assets/constants/request_types.js new file mode 100644 index 00000000..22f0d0ce --- /dev/null +++ b/server/controllers/assets/constants/request_types.js @@ -0,0 +1,9 @@ +const EMBED = 'EMBED'; +const BROWSER = 'BROWSER'; +const SOCIAL = 'SOCIAL'; + +module.exports = { + EMBED, + BROWSER, + SOCIAL, +}; diff --git a/server/controllers/assets/serveAsset/index.js b/server/controllers/assets/serveAsset/index.js new file mode 100644 index 00000000..3f0149a8 --- /dev/null +++ b/server/controllers/assets/serveAsset/index.js @@ -0,0 +1,17 @@ +const { sendGAServeEvent } = require('../../../utils/googleAnalytics'); +const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js'); + +/* + + route to serve an asset directly + +*/ + +const serveAsset = ({ headers, ip, originalUrl, params: { claimName, claimId } }, res) => { + // send google analytics + sendGAServeEvent(headers, ip, originalUrl); + // get the claim Id and then serve the asset + getClaimIdAndServeAsset(null, null, claimName, claimId, originalUrl, ip, res); +}; + +module.exports = serveAsset; diff --git a/server/controllers/assets/serveByClaim/index.js b/server/controllers/assets/serveByClaim/index.js index a561754e..6e0e9e40 100644 --- a/server/controllers/assets/serveByClaim/index.js +++ b/server/controllers/assets/serveByClaim/index.js @@ -3,11 +3,10 @@ const handleShowRender = require('../../../render/build/handleShowRender.js'); const lbryUri = require('../utils/lbryUri.js'); -const determineResponseType = require('../utils/determineResponseType.js'); +const determineRequestType = require('../utils/determineRequestType.js'); const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js'); -const logRequestData = require('../utils/logRequestData.js'); -const SERVE = 'SERVE'; +const { EMBED } = require('../constants/request_types.js'); /* @@ -15,7 +14,7 @@ const SERVE = 'SERVE'; */ -const serverAssetByClaim = (req, res) => { +const serveByClaim = (req, res) => { const { headers, ip, originalUrl, params } = req; // decide if this is a show request let hasFileExtension; @@ -24,13 +23,11 @@ const serverAssetByClaim = (req, res) => { } catch (error) { return res.status(400).json({success: false, message: error.message}); } - let responseType = determineResponseType(hasFileExtension, headers); - if (responseType !== SERVE) { + // determine request type + let requestType = determineRequestType(hasFileExtension, headers); + if (requestType !== EMBED) { return handleShowRender(req, res); } - // handle serve request - // send google analytics - sendGAServeEvent(headers, ip, originalUrl); // parse the claim let claimName; try { @@ -38,10 +35,10 @@ const serverAssetByClaim = (req, res) => { } catch (error) { return res.status(400).json({success: false, message: error.message}); } - // log the request data for debugging - logRequestData(responseType, claimName, null, null); + // send google analytics + sendGAServeEvent(headers, ip, originalUrl); // get the claim Id and then serve the asset getClaimIdAndServeAsset(null, null, claimName, null, originalUrl, ip, res); }; -module.exports = serverAssetByClaim; +module.exports = serveByClaim; diff --git a/server/controllers/assets/serveByIdentifierAndClaim/index.js b/server/controllers/assets/serveByIdentifierAndClaim/index.js index e493e01e..609a1256 100644 --- a/server/controllers/assets/serveByIdentifierAndClaim/index.js +++ b/server/controllers/assets/serveByIdentifierAndClaim/index.js @@ -3,12 +3,11 @@ const handleShowRender = require('../../../render/build/handleShowRender.js'); const lbryUri = require('../utils/lbryUri.js'); -const determineResponseType = require('../utils/determineResponseType.js'); +const determineRequestType = require('../utils/determineRequestType.js'); const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js'); const flipClaimNameAndId = require('../utils/flipClaimNameAndId.js'); -const logRequestData = require('../utils/logRequestData.js'); -const SERVE = 'SERVE'; +const { EMBED } = require('../constants/request_types.js'); /* @@ -16,22 +15,20 @@ const SERVE = 'SERVE'; */ -const serverAssetByIdentifierAndClaim = (req, res) => { +const serverByIdentifierAndClaim = (req, res) => { const { headers, ip, originalUrl, params } = req; - // decide if this is a show request + // parse request let hasFileExtension; try { ({ hasFileExtension } = lbryUri.parseModifier(params.claim)); } catch (error) { return res.status(400).json({success: false, message: error.message}); } - let responseType = determineResponseType(hasFileExtension, headers); - if (responseType !== SERVE) { + // determine request type + let requestType = determineRequestType(hasFileExtension, headers); + if (requestType !== EMBED) { return handleShowRender(req, res); } - // handle serve request - // send google analytics - sendGAServeEvent(headers, ip, originalUrl); // parse the claim let claimName; try { @@ -50,10 +47,10 @@ const serverAssetByIdentifierAndClaim = (req, res) => { if (!isChannel) { [claimId, claimName] = flipClaimNameAndId(claimId, claimName); } - // log the request data for debugging - logRequestData(responseType, claimName, channelName, claimId); + // send google analytics + sendGAServeEvent(headers, ip, originalUrl); // get the claim Id and then serve the asset getClaimIdAndServeAsset(channelName, channelClaimId, claimName, claimId, originalUrl, ip, res); }; -module.exports = serverAssetByIdentifierAndClaim; +module.exports = serverByIdentifierAndClaim; diff --git a/server/controllers/assets/utils/determineRequestType.js b/server/controllers/assets/utils/determineRequestType.js new file mode 100644 index 00000000..afc5574f --- /dev/null +++ b/server/controllers/assets/utils/determineRequestType.js @@ -0,0 +1,60 @@ +const logger = require('winston'); +const { EMBED, BROWSER, SOCIAL } = require('../constants/request_types.js'); + +function headersMatchesSocialBotList (headers) { + const userAgent = headers['user-agent']; + const socialBotList = [ + 'facebookexternalhit', + 'Twitterbot', + ]; + for (let i = 0; i < socialBotList.length; i++) { + if (userAgent.includes(socialBotList[i])) { + logger.debug('request is from social bot:', socialBotList[i]); + return true; + } + } + return false; +} + +function clientAcceptsHtml ({accept}) { + return accept && accept.match(/text\/html/); +} + +function requestIsFromBrowser (headers) { + return headers['user-agent'] && headers['user-agent'].match(/Mozilla/); +} + +function clientWantsAsset ({accept, range}) { + const imageIsWanted = accept && accept.match(/image\/.*/) && !accept.match(/text\/html/) && !accept.match(/text\/\*/); + const videoIsWanted = accept && range; + return imageIsWanted || videoIsWanted; +} + +const determineRequestType = (hasFileExtension, headers) => { + let responseType; + logger.debug('headers:', headers); + // return early with 'show' if headers match the list + if (headersMatchesSocialBotList(headers)) { + return SOCIAL; + } + // if request is not from a social bot... + if (hasFileExtension) { + // assume embed, + responseType = EMBED; + // but change to browser if client accepts html. + if (clientAcceptsHtml(headers)) { + responseType = BROWSER; + } + // if request does not have file extentsion... + } else { + // assume browser, + responseType = BROWSER; + // but change to embed if someone embeded a show url... + if (clientWantsAsset(headers) && requestIsFromBrowser(headers)) { + responseType = EMBED; + } + } + return responseType; +}; + +module.exports = determineRequestType; diff --git a/server/controllers/assets/utils/determineResponseType.js b/server/controllers/assets/utils/determineResponseType.js deleted file mode 100644 index f32a0c5c..00000000 --- a/server/controllers/assets/utils/determineResponseType.js +++ /dev/null @@ -1,37 +0,0 @@ -const logger = require('winston'); - -const SERVE = 'SERVE'; -const SHOW = 'SHOW'; - -function clientAcceptsHtml ({accept}) { - return accept && accept.match(/text\/html/); -}; - -function requestIsFromBrowser (headers) { - return headers['user-agent'] && headers['user-agent'].match(/Mozilla/); -}; - -function clientWantsAsset ({accept, range}) { - const imageIsWanted = accept && accept.match(/image\/.*/) && !accept.match(/text\/html/) && !accept.match(/text\/\*/); - const videoIsWanted = accept && range; - return imageIsWanted || videoIsWanted; -}; - -const determineResponseType = (hasFileExtension, headers) => { - let responseType; - if (hasFileExtension) { - responseType = SERVE; // assume a serve request if file extension is present - if (clientAcceptsHtml(headers)) { // if the request comes from a browser, change it to a show request - responseType = SHOW; - } - } else { - responseType = SHOW; - if (clientWantsAsset(headers) && requestIsFromBrowser(headers)) { // this is in case someone embeds a show url - logger.debug('Show request came from browser but wants an image/video. Changing response to serve...'); - responseType = SERVE; - } - } - return responseType; -}; - -module.exports = determineResponseType; diff --git a/server/controllers/assets/utils/getClaimIdAndServeAsset.js b/server/controllers/assets/utils/getClaimIdAndServeAsset.js index e391383d..6603d046 100644 --- a/server/controllers/assets/utils/getClaimIdAndServeAsset.js +++ b/server/controllers/assets/utils/getClaimIdAndServeAsset.js @@ -17,7 +17,12 @@ const getClaimIdAndServeAsset = (channelName, channelClaimId, claimName, claimId getClaimId(channelName, channelClaimId, claimName, claimId) .then(fullClaimId => { claimId = fullClaimId; - return db.Blocked.isNotBlocked(fullClaimId, claimName); + logger.debug('Full claim id:', fullClaimId); + return db.Claim.getOutpoint(claimName, fullClaimId); + }) + .then(outpoint => { + logger.debug('Outpoint:', outpoint); + return db.Blocked.isNotBlocked(outpoint); }) .then(() => { return getLocalFileRecord(claimId, claimName); diff --git a/server/controllers/pages/sendEmbedPage.js b/server/controllers/pages/sendVideoEmbedPage.js similarity index 73% rename from server/controllers/pages/sendEmbedPage.js rename to server/controllers/pages/sendVideoEmbedPage.js index d4bef437..01f6b1f4 100644 --- a/server/controllers/pages/sendEmbedPage.js +++ b/server/controllers/pages/sendVideoEmbedPage.js @@ -1,10 +1,10 @@ const { details: { host } } = require('@config/siteConfig'); -const sendEmbedPage = ({ params }, res) => { +const sendVideoEmbedPage = ({ params }, res) => { const claimId = params.claimId; const name = params.name; // get and render the content res.status(200).render('embed', { layout: 'embed', host, claimId, name }); }; -module.exports = sendEmbedPage; +module.exports = sendVideoEmbedPage; diff --git a/server/lbrynet/index.js b/server/lbrynet/index.js index bab4ede0..4ff64521 100644 --- a/server/lbrynet/index.js +++ b/server/lbrynet/index.js @@ -1,6 +1,6 @@ const axios = require('axios'); const logger = require('winston'); -const { apiHost, apiPort } = require('@config/lbryConfig'); +const { apiHost, apiPort, getTimeout } = require('@config/lbryConfig'); const lbrynetUri = 'http://' + apiHost + ':' + apiPort; const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('../utils/googleAnalytics.js'); const handleLbrynetResponse = require('./utils/handleLbrynetResponse.js'); @@ -31,7 +31,10 @@ module.exports = { axios .post(lbrynetUri, { method: 'get', - params: { uri, timeout: 20 }, + params: { + uri, + timeout: getTimeout || 30, + }, }) .then(response => { sendGATimingEvent('lbrynet', 'getClaim', 'GET', gaStartTime, Date.now()); diff --git a/server/routes/utils/multipartMiddleware.js b/server/middleware/multipartMiddleware.js similarity index 100% rename from server/routes/utils/multipartMiddleware.js rename to server/middleware/multipartMiddleware.js diff --git a/server/middleware/torCheckMiddleware.js b/server/middleware/torCheckMiddleware.js new file mode 100644 index 00000000..62c42af5 --- /dev/null +++ b/server/middleware/torCheckMiddleware.js @@ -0,0 +1,31 @@ +const logger = require('winston'); +const db = require('../models'); + +const torCheck = (req, res, next) => { + const { ip } = req; + logger.debug(`tor check for: ${ip}`); + return db.Tor.findAll( + { + where: { + address: ip, + }, + raw: true, + }) + .then(result => { + if (result.length >= 1) { + logger.info('Tor request blocked:', ip); + const failureResponse = { + success: false, + message: 'Unfortunately this api route is not currently available for tor users. We are working on a solution that will allow tor users to use this endpoint in the future.', + }; + res.status(403).json(failureResponse); + } else { + return next(); + } + }) + .catch(error => { + logger.error(error); + }); +}; + +module.exports = torCheck; diff --git a/server/models/blocked.js b/server/models/blocked.js index 12a04ca9..5e413889 100644 --- a/server/models/blocked.js +++ b/server/models/blocked.js @@ -6,14 +6,6 @@ module.exports = (sequelize, { STRING }) => { const Blocked = sequelize.define( 'Blocked', { - claimId: { - type : STRING, - allowNull: false, - }, - name: { - type : STRING, - allowNull: false, - }, outpoint: { type : STRING, allowNull: false, @@ -24,13 +16,12 @@ module.exports = (sequelize, { STRING }) => { } ); - Blocked.isNotBlocked = function (claimId, name) { - logger.debug(`checking to see if ${name}#${claimId} is not blocked`); + Blocked.isNotBlocked = function (outpoint) { + logger.debug(`checking to see if ${outpoint} is not blocked`); return new Promise((resolve, reject) => { this.findOne({ where: { - claimId, - name, + outpoint, }, }) .then(result => { @@ -46,5 +37,39 @@ module.exports = (sequelize, { STRING }) => { }); }; + Blocked.refreshTable = function () { + let blockedList = []; + return fetch('https://api.lbry.io/file/list_blocked') + .then(response => { + return response.json(); + }) + .then(jsonResponse => { + if (!jsonResponse.data) { + throw new Error('no data in list_blocked response'); + } + if (!jsonResponse.data.outpoints) { + throw new Error('no outpoints in list_blocked response'); + } + return jsonResponse.data.outpoints; + }) + .then(outpoints => { + logger.debug('total outpoints:', outpoints.length); + // prep the records + for (let i = 0; i < outpoints.length; i++) { + blockedList.push({ + outpoint: outpoints[i], + }); + } + // clear the table + return this.destroy({ + truncate: true, + }); + }) + .then(() => { + // fill the table + return this.bulkCreate(blockedList); + }); + }; + return Blocked; }; diff --git a/server/models/claim.js b/server/models/claim.js index 128d76ee..7e2a5f61 100644 --- a/server/models/claim.js +++ b/server/models/claim.js @@ -378,5 +378,27 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => { }); }; + Claim.getOutpoint = function (name, claimId) { + return this + .findAll({ + where : { name, claimId }, + attributes: ['outpoint'], + }) + .then(result => { + logger.debug('outpoint result'); + switch (result.length) { + case 0: + throw new Error(`no record found for ${name}#${claimId}`); + case 1: + return result[0].dataValues.outpoint; + default: + throw new Error(`more than one record found for ${name}#${claimId}`); + } + }) + .catch(error => { + throw error; + }); + }; + return Claim; }; diff --git a/server/models/index.js b/server/models/index.js index e2011bc8..a13d58ec 100644 --- a/server/models/index.js +++ b/server/models/index.js @@ -8,6 +8,7 @@ const File = require('./file.js'); const Request = require('./request.js'); const User = require('./user.js'); const Blocked = require('./blocked.js'); +const Tor = require('./tor.js'); const {database, username, password} = require('@config/mysqlConfig'); if (!database || !username || !password) { @@ -50,6 +51,7 @@ db['File'] = sequelize.import('File', File); db['Request'] = sequelize.import('Request', Request); db['User'] = sequelize.import('User', User); db['Blocked'] = sequelize.import('Blocked', Blocked); +db['Tor'] = sequelize.import('Tor', Tor); // run model.association for each model in the db object that has an association logger.info('associating db models...'); diff --git a/server/models/tor.js b/server/models/tor.js new file mode 100644 index 00000000..a314e92d --- /dev/null +++ b/server/models/tor.js @@ -0,0 +1,59 @@ +const logger = require('winston'); +const { details: { ipAddress } } = require('@config/siteConfig'); + +module.exports = (sequelize, { STRING }) => { + const Tor = sequelize.define( + 'Tor', + { + address: { + type : STRING, + allowNull: false, + }, + fingerprint: { + type : STRING, + allowNull: true, + }, + }, + { + freezeTableName: true, + } + ); + + Tor.refreshTable = function () { + let torList = []; + return fetch(`https://check.torproject.org/api/bulk?ip=${ipAddress}&port=80`) + .then(response => { + return response.json(); + }) + .then(jsonResponse => { + logger.debug('total tor nodes:', jsonResponse.length); + // prep the records + for (let i = 0; i < jsonResponse.length; i++) { + torList.push({ + address : jsonResponse[i].Address, + fingerprint: jsonResponse[i].Fingerprint, + }); + } + // clear the table + return this.destroy({ + truncate: true, + }); + }) + .then(() => { + // fill the table + return this.bulkCreate(torList); + }) + .then(() => { + // return the new table + return this.findAll({ + attributes: ['address', 'fingerprint'], + raw : true, + }); + }) + .catch(error => { + throw error; + }); + }; + + return Tor; +}; diff --git a/server/routes/api/index.js b/server/routes/api/index.js index 0aabd472..bb24e5b2 100644 --- a/server/routes/api/index.js +++ b/server/routes/api/index.js @@ -1,9 +1,12 @@ +// middleware +const multipartMiddleware = require('../../middleware/multipartMiddleware'); +const torCheckMiddleware = require('../../middleware/torCheckMiddleware'); +// route handlers const channelAvailability = require('../../controllers/api/channel/availability'); const channelClaims = require('../../controllers/api/channel/claims'); const channelData = require('../../controllers/api/channel/data'); const channelShortId = require('../../controllers/api/channel/shortId'); const claimAvailability = require('../../controllers/api/claim/availability'); -const claimBlockedList = require('../../controllers/api/claim/blockedList'); const claimData = require('../../controllers/api/claim/data/'); const claimGet = require('../../controllers/api/claim/get'); const claimList = require('../../controllers/api/claim/list'); @@ -13,27 +16,34 @@ const claimResolve = require('../../controllers/api/claim/resolve'); const claimShortId = require('../../controllers/api/claim/shortId'); const fileAvailability = require('../../controllers/api/file/availability'); const userPassword = require('../../controllers/api/user/password'); +const publishingConfig = require('../../controllers/api/config/site/publishing'); +const getTorList = require('../../controllers/api/tor'); +const getBlockedList = require('../../controllers/api/blocked'); -const multipartMiddleware = require('../utils/multipartMiddleware'); module.exports = (app) => { // channel routes - app.get('/api/channel/availability/:name', channelAvailability); - app.get('/api/channel/short-id/:longId/:name', channelShortId); - app.get('/api/channel/data/:channelName/:channelClaimId', channelData); - app.get('/api/channel/claims/:channelName/:channelClaimId/:page', channelClaims); + app.get('/api/channel/availability/:name', torCheckMiddleware, channelAvailability); + app.get('/api/channel/short-id/:longId/:name', torCheckMiddleware, channelShortId); + app.get('/api/channel/data/:channelName/:channelClaimId', torCheckMiddleware, channelData); + app.get('/api/channel/claims/:channelName/:channelClaimId/:page', torCheckMiddleware, channelClaims); // claim routes - app.get('/api/claim/availability/:name', claimAvailability); - app.get('/api/claim/blocked-list/', claimBlockedList); - app.get('/api/claim/data/:claimName/:claimId', claimData); - app.get('/api/claim/get/:name/:claimId', claimGet); - app.get('/api/claim/list/:name', claimList); - app.post('/api/claim/long-id', claimLongId); - app.post('/api/claim/publish', multipartMiddleware, claimPublish); - app.get('/api/claim/resolve/:name/:claimId', claimResolve); - app.get('/api/claim/short-id/:longId/:name', claimShortId); + app.get('/api/claim/availability/:name', torCheckMiddleware, claimAvailability); + app.get('/api/claim/data/:claimName/:claimId', torCheckMiddleware, claimData); + app.get('/api/claim/get/:name/:claimId', torCheckMiddleware, claimGet); + app.get('/api/claim/list/:name', torCheckMiddleware, claimList); + app.post('/api/claim/long-id', torCheckMiddleware, claimLongId); // note: should be a 'get' + app.post('/api/claim/publish', torCheckMiddleware, multipartMiddleware, claimPublish); + app.get('/api/claim/resolve/:name/:claimId', torCheckMiddleware, claimResolve); + app.get('/api/claim/short-id/:longId/:name', torCheckMiddleware, claimShortId); // file routes - app.get('/api/file/availability/:name/:claimId', fileAvailability); + app.get('/api/file/availability/:name/:claimId', torCheckMiddleware, fileAvailability); // user routes - app.put('/api/user/password/', userPassword); + app.put('/api/user/password/', torCheckMiddleware, userPassword); + // configs + app.get('/api/config/site/publishing', torCheckMiddleware, publishingConfig); + // tor + app.get('/api/tor', torCheckMiddleware, getTorList); + // blocked + app.get('/api/blocked', torCheckMiddleware, getBlockedList); }; diff --git a/server/routes/assets/index.js b/server/routes/assets/index.js index 4e87d2dd..5d4f92d1 100644 --- a/server/routes/assets/index.js +++ b/server/routes/assets/index.js @@ -1,7 +1,9 @@ -const serveAssetByClaim = require('../../controllers/assets/serveByClaim'); -const serveAssetByIdentifierAndClaim = require('../../controllers/assets/serveByIdentifierAndClaim'); +const serveByClaim = require('../../controllers/assets/serveByClaim'); +const serveByIdentifierAndClaim = require('../../controllers/assets/serveByIdentifierAndClaim'); +const serveAsset = require('../../controllers/assets/serveAsset'); -module.exports = (app, db) => { - app.get('/:identifier/:claim', serveAssetByIdentifierAndClaim); - app.get('/:claim', serveAssetByClaim); +module.exports = (app) => { + app.get('/asset/:claimName/:claimId/', serveAsset); + app.get('/:identifier/:claim', serveByIdentifierAndClaim); + app.get('/:claim', serveByClaim); }; diff --git a/server/routes/pages/index.js b/server/routes/pages/index.js index 2c62b1aa..2dff606b 100644 --- a/server/routes/pages/index.js +++ b/server/routes/pages/index.js @@ -1,5 +1,5 @@ const handlePageRequest = require('../../controllers/pages/sendReactApp'); -const handleEmbedRequest = require('../../controllers/pages/sendEmbedPage'); +const handleVideoEmbedRequest = require('../../controllers/pages/sendVideoEmbedPage'); const redirect = require('../../controllers/utils/redirect'); module.exports = (app) => { @@ -10,5 +10,5 @@ module.exports = (app) => { app.get('/popular', handlePageRequest); app.get('/new', handlePageRequest); app.get('/multisite', handlePageRequest); - app.get('/embed/:claimId/:name', handleEmbedRequest); // route to send embedable video player (for twitter) + app.get('/video-embed/:name/:claimId', handleVideoEmbedRequest); // for twitter }; diff --git a/test/test.html b/test/test.html new file mode 100644 index 00000000..01a5d622 --- /dev/null +++ b/test/test.html @@ -0,0 +1,21 @@ + + + + + + + Document + + + test embed +

no identifier, no ending

+ no identifier, no ending +

no identifier, yes ending

+ no identifier, yes ending +

yes identifier, no ending

+ yes identifier, no ending +

yes identifier, yes ending

+ yes identifier, yes ending + +