Merge branch 'master' into dependencies-upgrade
This commit is contained in:
commit
1757d586cb
38 changed files with 719 additions and 328 deletions
38
client/build/components/AssetShareButtons/index.js
Normal file
38
client/build/components/AssetShareButtons/index.js
Normal file
|
@ -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;
|
82
client/build/components/ClickToCopy/index.js
Normal file
82
client/build/components/ClickToCopy/index.js
Normal file
|
@ -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;
|
|
@ -17,6 +17,10 @@ var _Row = _interopRequireDefault(require("@components/Row"));
|
||||||
|
|
||||||
var _SpaceBetween = _interopRequireDefault(require("@components/SpaceBetween"));
|
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 _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 _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 _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; }
|
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) {
|
function _getPrototypeOf(o) { _getPrototypeOf = Object.getPrototypeOf || function _getPrototypeOf(o) { return o.__proto__; }; return _getPrototypeOf(o); }
|
||||||
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"
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var AssetInfo =
|
var AssetInfo =
|
||||||
/*#__PURE__*/
|
/*#__PURE__*/
|
||||||
function (_React$Component) {
|
function (_React$Component) {
|
||||||
function AssetInfo(props) {
|
function AssetInfo() {
|
||||||
var _this;
|
|
||||||
|
|
||||||
_classCallCheck(this, AssetInfo);
|
_classCallCheck(this, AssetInfo);
|
||||||
|
|
||||||
_this = _possibleConstructorReturn(this, _getPrototypeOf(AssetInfo).call(this, props));
|
return _possibleConstructorReturn(this, _getPrototypeOf(AssetInfo).apply(this, arguments));
|
||||||
_this.copyToClipboard = _this.copyToClipboard.bind(_assertThisInitialized(_assertThisInitialized(_this)));
|
|
||||||
return _this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_createClass(AssetInfo, [{
|
_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",
|
key: "render",
|
||||||
value: function render() {
|
value: function render() {
|
||||||
var _this$props$asset = this.props.asset,
|
var _this$props$asset = this.props.asset,
|
||||||
|
@ -134,31 +78,29 @@ function (_React$Component) {
|
||||||
label: _react.default.createElement(_Label.default, {
|
label: _react.default.createElement(_Label.default, {
|
||||||
value: 'Share:'
|
value: 'Share:'
|
||||||
}),
|
}),
|
||||||
content: _react.default.createElement(AssetShareButtons, {
|
content: _react.default.createElement(_AssetShareButtons.default, {
|
||||||
host: host,
|
host: host,
|
||||||
|
name: name,
|
||||||
shortId: shortId
|
shortId: shortId
|
||||||
})
|
})
|
||||||
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_RowLabeled.default, {
|
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_RowLabeled.default, {
|
||||||
label: _react.default.createElement(_Label.default, {
|
label: _react.default.createElement(_Label.default, {
|
||||||
value: 'Link:'
|
value: 'Link:'
|
||||||
}),
|
}),
|
||||||
content: _react.default.createElement(ClickToCopy, {
|
content: _react.default.createElement(_ClickToCopy.default, {
|
||||||
id: 'short-link',
|
id: 'short-link',
|
||||||
value: "".concat(host, "/").concat(shortId, "/").concat(name, ".").concat(fileExt),
|
value: "".concat(host, "/").concat(shortId, "/").concat(name, ".").concat(fileExt)
|
||||||
copyToClipboard: this.copyToClipboard
|
|
||||||
})
|
})
|
||||||
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_RowLabeled.default, {
|
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_RowLabeled.default, {
|
||||||
label: _react.default.createElement(_Label.default, {
|
label: _react.default.createElement(_Label.default, {
|
||||||
value: 'Embed:'
|
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',
|
id: 'embed-text-video',
|
||||||
value: "<video width=\"100%\" controls poster=\"".concat(thumbnail, "\" src=\"").concat(host, "/").concat(claimId, "/").concat(name, ".").concat(fileExt, "\"/></video>"),
|
value: "<video width=\"100%\" controls poster=\"".concat(thumbnail, "\" src=\"").concat(host, "/").concat(claimId, "/").concat(name, ".").concat(fileExt, "\"/></video>")
|
||||||
copyToClipboard: this.copyToClipboard
|
}) : _react.default.createElement(_ClickToCopy.default, {
|
||||||
}) : _react.default.createElement(ClickToCopy, {
|
|
||||||
id: 'embed-text-image',
|
id: 'embed-text-image',
|
||||||
value: "<img src=\"".concat(host, "/").concat(claimId, "/").concat(name, ".").concat(fileExt, "\"/>"),
|
value: "<img src=\"".concat(host, "/").concat(claimId, "/").concat(name, ".").concat(fileExt, "\"/>")
|
||||||
copyToClipboard: this.copyToClipboard
|
|
||||||
}))
|
}))
|
||||||
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_SpaceBetween.default, null, _react.default.createElement(_reactRouterDom.Link, {
|
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_SpaceBetween.default, null, _react.default.createElement(_reactRouterDom.Link, {
|
||||||
className: "link--primary",
|
className: "link--primary",
|
||||||
|
|
|
@ -40,11 +40,15 @@ function (_React$Component) {
|
||||||
key: "render",
|
key: "render",
|
||||||
value: function render() {
|
value: function render() {
|
||||||
var message = this.props.message;
|
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'
|
className: 'text--secondary'
|
||||||
}, "Publishing is currently disabled."), _react.default.createElement("p", {
|
}, "Publishing is currently disabled."), _react.default.createElement("p", {
|
||||||
className: 'text--secondary'
|
className: 'text--secondary'
|
||||||
}, message));
|
}, message)));
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
|
@ -101,9 +101,9 @@ var createAssetMetaTags = function createAssetMetaTags(_ref3) {
|
||||||
defaultThumbnail = _ref3.defaultThumbnail;
|
defaultThumbnail = _ref3.defaultThumbnail;
|
||||||
var claimData = asset.claimData;
|
var claimData = asset.claimData;
|
||||||
var contentType = claimData.contentType;
|
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 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 ogTitle = claimData.title || claimData.name;
|
||||||
var ogDescription = claimData.description || defaultDescription;
|
var ogDescription = claimData.description || defaultDescription;
|
||||||
var ogThumbnailContentType = determineOgThumbnailContentType(claimData.thumbnail);
|
var ogThumbnailContentType = determineOgThumbnailContentType(claimData.thumbnail);
|
||||||
|
@ -154,7 +154,7 @@ var createAssetMetaTags = function createAssetMetaTags(_ref3) {
|
||||||
});
|
});
|
||||||
metaTags.push({
|
metaTags.push({
|
||||||
property: 'og:type',
|
property: 'og:type',
|
||||||
content: 'video'
|
content: 'video.other'
|
||||||
});
|
});
|
||||||
metaTags.push({
|
metaTags.push({
|
||||||
property: 'twitter:card',
|
property: 'twitter:card',
|
||||||
|
@ -162,7 +162,7 @@ var createAssetMetaTags = function createAssetMetaTags(_ref3) {
|
||||||
});
|
});
|
||||||
metaTags.push({
|
metaTags.push({
|
||||||
property: 'twitter:player',
|
property: 'twitter:player',
|
||||||
content: embedUrl
|
content: videoEmbedUrl
|
||||||
});
|
});
|
||||||
metaTags.push({
|
metaTags.push({
|
||||||
property: 'twitter:player:width',
|
property: 'twitter:player:width',
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
@import 'containers/_dropzone';
|
@import 'containers/_dropzone';
|
||||||
@import 'containers/_publish-url-input';
|
@import 'containers/_publish-url-input';
|
||||||
@import 'containers/_publish-status';
|
@import 'containers/_publish-status';
|
||||||
|
@import 'containers/_publish-disabled-message';
|
||||||
|
|
||||||
@import '_media-queries';
|
@import '_media-queries';
|
||||||
|
|
||||||
|
|
11
client/scss/containers/_publish-disabled-message.scss
Normal file
11
client/scss/containers/_publish-disabled-message.scss
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
39
client/src/components/AssetShareButtons/index.js
Normal file
39
client/src/components/AssetShareButtons/index.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import React from 'react';
|
||||||
|
import SpaceBetween from '@components/SpaceBetween';
|
||||||
|
|
||||||
|
const AssetShareButtons = ({ host, name, shortId }) => {
|
||||||
|
return (
|
||||||
|
<SpaceBetween >
|
||||||
|
<a
|
||||||
|
className='link--primary'
|
||||||
|
target='_blank'
|
||||||
|
href={`https://twitter.com/intent/tweet?text=${host}/${shortId}/${name}`}
|
||||||
|
>
|
||||||
|
twitter
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className='link--primary'
|
||||||
|
target='_blank'
|
||||||
|
href={`https://www.facebook.com/sharer/sharer.php?u=${host}/${shortId}/${name}`}
|
||||||
|
>
|
||||||
|
facebook
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className='link--primary'
|
||||||
|
target='_blank'
|
||||||
|
href={`http://tumblr.com/widgets/share/tool?canonicalUrl=${host}/${shortId}/${name}`}
|
||||||
|
>
|
||||||
|
tumblr
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className='link--primary'
|
||||||
|
target='_blank'
|
||||||
|
href={`https://www.reddit.com/submit?url=${host}/${shortId}/${name}&title=${name}`}
|
||||||
|
>
|
||||||
|
reddit
|
||||||
|
</a>
|
||||||
|
</SpaceBetween>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AssetShareButtons;
|
34
client/src/components/ClickToCopy/index.jsx
Normal file
34
client/src/components/ClickToCopy/index.jsx
Normal file
|
@ -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 (
|
||||||
|
<input
|
||||||
|
id={id}
|
||||||
|
value={value}
|
||||||
|
onClick={this.copyToClipboard}
|
||||||
|
type='text'
|
||||||
|
className='click-to-copy'
|
||||||
|
readOnly
|
||||||
|
spellCheck='false'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ClickToCopy;
|
|
@ -4,74 +4,10 @@ import Label from '@components/Label';
|
||||||
import RowLabeled from '@components/RowLabeled';
|
import RowLabeled from '@components/RowLabeled';
|
||||||
import Row from '@components/Row';
|
import Row from '@components/Row';
|
||||||
import SpaceBetween from '@components/SpaceBetween';
|
import SpaceBetween from '@components/SpaceBetween';
|
||||||
|
import AssetShareButtons from '@components/AssetShareButtons';
|
||||||
const AssetShareButtons = ({ host, name, shortId }) => {
|
import ClickToCopy from '@components/ClickToCopy';
|
||||||
return (
|
|
||||||
<SpaceBetween >
|
|
||||||
<a
|
|
||||||
className='link--primary'
|
|
||||||
target='_blank'
|
|
||||||
href={`https://twitter.com/intent/tweet?text=${host}/${shortId}/${name}`}
|
|
||||||
>
|
|
||||||
twitter
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className='link--primary'
|
|
||||||
target='_blank'
|
|
||||||
href={`https://www.facebook.com/sharer/sharer.php?u=${host}/${shortId}/${name}`}
|
|
||||||
>
|
|
||||||
facebook
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className='link--primary'
|
|
||||||
target='_blank'
|
|
||||||
href={`http://tumblr.com/widgets/share/tool?canonicalUrl=${host}/${shortId}/${name}`}
|
|
||||||
>
|
|
||||||
tumblr
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className='link--primary'
|
|
||||||
target='_blank'
|
|
||||||
href={`https://www.reddit.com/submit?url=${host}/${shortId}/${name}&title=${name}`}
|
|
||||||
>
|
|
||||||
reddit
|
|
||||||
</a>
|
|
||||||
</SpaceBetween>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ClickToCopy = ({id, value, copyToClipboard}) => {
|
|
||||||
return (
|
|
||||||
<input
|
|
||||||
id={id}
|
|
||||||
value={value}
|
|
||||||
onClick={copyToClipboard}
|
|
||||||
type='text'
|
|
||||||
className='click-to-copy'
|
|
||||||
readOnly
|
|
||||||
spellCheck='false'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
class AssetInfo extends React.Component {
|
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 () {
|
render () {
|
||||||
const { asset: { shortId, claimData : { channelName, certificateId, description, name, claimId, fileExt, contentType, thumbnail, host } } } = this.props;
|
const { asset: { shortId, claimData : { channelName, certificateId, description, name, claimId, fileExt, contentType, thumbnail, host } } } = this.props;
|
||||||
return (
|
return (
|
||||||
|
@ -99,6 +35,7 @@ class AssetInfo extends React.Component {
|
||||||
content={
|
content={
|
||||||
<AssetShareButtons
|
<AssetShareButtons
|
||||||
host={host}
|
host={host}
|
||||||
|
name={name}
|
||||||
shortId={shortId}
|
shortId={shortId}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
@ -114,7 +51,6 @@ class AssetInfo extends React.Component {
|
||||||
<ClickToCopy
|
<ClickToCopy
|
||||||
id={'short-link'}
|
id={'short-link'}
|
||||||
value={`${host}/${shortId}/${name}.${fileExt}`}
|
value={`${host}/${shortId}/${name}.${fileExt}`}
|
||||||
copyToClipboard={this.copyToClipboard}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -131,13 +67,11 @@ class AssetInfo extends React.Component {
|
||||||
<ClickToCopy
|
<ClickToCopy
|
||||||
id={'embed-text-video'}
|
id={'embed-text-video'}
|
||||||
value={`<video width="100%" controls poster="${thumbnail}" src="${host}/${claimId}/${name}.${fileExt}"/></video>`}
|
value={`<video width="100%" controls poster="${thumbnail}" src="${host}/${claimId}/${name}.${fileExt}"/></video>`}
|
||||||
copyToClipboard={this.copyToClipboard}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ClickToCopy
|
<ClickToCopy
|
||||||
id={'embed-text-image'}
|
id={'embed-text-image'}
|
||||||
value={`<img src="${host}/${claimId}/${name}.${fileExt}"/>`}
|
value={`<img src="${host}/${claimId}/${name}.${fileExt}"/>`}
|
||||||
copyToClipboard={this.copyToClipboard}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,10 +4,12 @@ class PublishDisabledMessage extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
const message = this.props.message;
|
const message = this.props.message;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={'publish-disabled-message'}>
|
||||||
|
<div className={'message'}>
|
||||||
<p className={'text--secondary'}>Publishing is currently disabled.</p>
|
<p className={'text--secondary'}>Publishing is currently disabled.</p>
|
||||||
<p className={'text--secondary'}>{message}</p>
|
<p className={'text--secondary'}>{message}</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,9 +46,9 @@ const createChannelMetaTags = ({siteHost, siteTitle, siteTwitter, channel}) => {
|
||||||
const createAssetMetaTags = ({siteHost, siteTitle, siteTwitter, asset, defaultDescription, defaultThumbnail}) => {
|
const createAssetMetaTags = ({siteHost, siteTitle, siteTwitter, asset, defaultDescription, defaultThumbnail}) => {
|
||||||
const { claimData } = asset;
|
const { claimData } = asset;
|
||||||
const { contentType } = claimData;
|
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 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 ogTitle = claimData.title || claimData.name;
|
||||||
const ogDescription = claimData.description || defaultDescription;
|
const ogDescription = claimData.description || defaultDescription;
|
||||||
const ogThumbnailContentType = determineOgThumbnailContentType(claimData.thumbnail);
|
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:video:type', content: contentType});
|
||||||
metaTags.push({property: 'og:image', content: ogThumbnail});
|
metaTags.push({property: 'og:image', content: ogThumbnail});
|
||||||
metaTags.push({property: 'og:image:type', content: ogThumbnailContentType});
|
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: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:player:width', content: 600});
|
||||||
metaTags.push({property: 'twitter:text:player_width', content: 600});
|
metaTags.push({property: 'twitter:text:player_width', content: 600});
|
||||||
metaTags.push({property: 'twitter:player:height', content: 337});
|
metaTags.push({property: 'twitter:player:height', content: 337});
|
||||||
|
|
63
index.js
63
index.js
|
@ -35,6 +35,10 @@ const speechPassport = require('./server/speechPassport');
|
||||||
const {
|
const {
|
||||||
details: { port: PORT },
|
details: { port: PORT },
|
||||||
auth: { sessionKey },
|
auth: { sessionKey },
|
||||||
|
startup: {
|
||||||
|
performChecks,
|
||||||
|
performUpdates,
|
||||||
|
},
|
||||||
} = require('@config/siteConfig');
|
} = require('@config/siteConfig');
|
||||||
|
|
||||||
function Server () {
|
function Server () {
|
||||||
|
@ -97,31 +101,70 @@ function Server () {
|
||||||
/* create server */
|
/* create server */
|
||||||
this.server = http.Server(this.app);
|
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 = () => {
|
this.syncDatabase = () => {
|
||||||
|
logger.info(`Syncing database...`);
|
||||||
return createDatabaseIfNotExists()
|
return createDatabaseIfNotExists()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
db.sequelize.sync();
|
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.start = () => {
|
||||||
this.initialize();
|
this.initialize();
|
||||||
this.createApp();
|
this.createApp();
|
||||||
this.createServer();
|
this.createServer();
|
||||||
/* start the server */
|
this.syncDatabase()
|
||||||
logger.info('getting LBC balance & syncing database...');
|
.then(() => {
|
||||||
Promise.all([
|
return this.startServerListening();
|
||||||
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}`);
|
|
||||||
})
|
})
|
||||||
|
.then(() => {
|
||||||
|
return Promise.all([
|
||||||
|
this.performChecks(),
|
||||||
|
this.performUpdates(),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
logger.info('Spee.ch startup is complete');
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (error.code === 'ECONNREFUSED') {
|
if (error.code === 'ECONNREFUSED') {
|
||||||
return logger.error('Connection refused. The daemon may not be running.')
|
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) {
|
} else if (error.message) {
|
||||||
logger.error(error.message);
|
logger.error(error.message);
|
||||||
}
|
}
|
||||||
|
|
22
server/controllers/api/blocked/index.js
Normal file
22
server/controllers/api/blocked/index.js
Normal file
|
@ -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;
|
|
@ -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;
|
|
|
@ -22,7 +22,10 @@ const claimLongId = ({ ip, originalUrl, body, params }, res) => {
|
||||||
getClaimId(channelName, channelClaimId, claimName, claimId)
|
getClaimId(channelName, channelClaimId, claimName, claimId)
|
||||||
.then(fullClaimId => {
|
.then(fullClaimId => {
|
||||||
claimId = fullClaimId;
|
claimId = fullClaimId;
|
||||||
return db.Blocked.isNotBlocked(fullClaimId, claimName);
|
return db.Claim.getOutpoint(claimName, fullClaimId);
|
||||||
|
})
|
||||||
|
.then(outpoint => {
|
||||||
|
return db.Blocked.isNotBlocked(outpoint);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
res.status(200).json({success: true, data: claimId});
|
res.status(200).json({success: true, data: claimId});
|
||||||
|
|
|
@ -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');
|
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
|
// define variables
|
||||||
let channelName, channelId, channelPassword, description, fileName, filePath, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title;
|
let channelName, channelId, channelPassword, description, fileName, filePath, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title;
|
||||||
// record the start time of the request
|
// record the start time of the request
|
||||||
|
|
29
server/controllers/api/config/site/publishing/index.js
Normal file
29
server/controllers/api/config/site/publishing/index.js
Normal file
|
@ -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;
|
25
server/controllers/api/tor/index.js
Normal file
25
server/controllers/api/tor/index.js
Normal file
|
@ -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;
|
9
server/controllers/assets/constants/request_types.js
Normal file
9
server/controllers/assets/constants/request_types.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
const EMBED = 'EMBED';
|
||||||
|
const BROWSER = 'BROWSER';
|
||||||
|
const SOCIAL = 'SOCIAL';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
EMBED,
|
||||||
|
BROWSER,
|
||||||
|
SOCIAL,
|
||||||
|
};
|
17
server/controllers/assets/serveAsset/index.js
Normal file
17
server/controllers/assets/serveAsset/index.js
Normal file
|
@ -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;
|
|
@ -3,11 +3,10 @@ const handleShowRender = require('../../../render/build/handleShowRender.js');
|
||||||
|
|
||||||
const lbryUri = require('../utils/lbryUri.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 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;
|
const { headers, ip, originalUrl, params } = req;
|
||||||
// decide if this is a show request
|
// decide if this is a show request
|
||||||
let hasFileExtension;
|
let hasFileExtension;
|
||||||
|
@ -24,13 +23,11 @@ const serverAssetByClaim = (req, res) => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).json({success: false, message: error.message});
|
return res.status(400).json({success: false, message: error.message});
|
||||||
}
|
}
|
||||||
let responseType = determineResponseType(hasFileExtension, headers);
|
// determine request type
|
||||||
if (responseType !== SERVE) {
|
let requestType = determineRequestType(hasFileExtension, headers);
|
||||||
|
if (requestType !== EMBED) {
|
||||||
return handleShowRender(req, res);
|
return handleShowRender(req, res);
|
||||||
}
|
}
|
||||||
// handle serve request
|
|
||||||
// send google analytics
|
|
||||||
sendGAServeEvent(headers, ip, originalUrl);
|
|
||||||
// parse the claim
|
// parse the claim
|
||||||
let claimName;
|
let claimName;
|
||||||
try {
|
try {
|
||||||
|
@ -38,10 +35,10 @@ const serverAssetByClaim = (req, res) => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).json({success: false, message: error.message});
|
return res.status(400).json({success: false, message: error.message});
|
||||||
}
|
}
|
||||||
// log the request data for debugging
|
// send google analytics
|
||||||
logRequestData(responseType, claimName, null, null);
|
sendGAServeEvent(headers, ip, originalUrl);
|
||||||
// get the claim Id and then serve the asset
|
// get the claim Id and then serve the asset
|
||||||
getClaimIdAndServeAsset(null, null, claimName, null, originalUrl, ip, res);
|
getClaimIdAndServeAsset(null, null, claimName, null, originalUrl, ip, res);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = serverAssetByClaim;
|
module.exports = serveByClaim;
|
||||||
|
|
|
@ -3,12 +3,11 @@ const handleShowRender = require('../../../render/build/handleShowRender.js');
|
||||||
|
|
||||||
const lbryUri = require('../utils/lbryUri.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 getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js');
|
||||||
const flipClaimNameAndId = require('../utils/flipClaimNameAndId.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;
|
const { headers, ip, originalUrl, params } = req;
|
||||||
// decide if this is a show request
|
// parse request
|
||||||
let hasFileExtension;
|
let hasFileExtension;
|
||||||
try {
|
try {
|
||||||
({ hasFileExtension } = lbryUri.parseModifier(params.claim));
|
({ hasFileExtension } = lbryUri.parseModifier(params.claim));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).json({success: false, message: error.message});
|
return res.status(400).json({success: false, message: error.message});
|
||||||
}
|
}
|
||||||
let responseType = determineResponseType(hasFileExtension, headers);
|
// determine request type
|
||||||
if (responseType !== SERVE) {
|
let requestType = determineRequestType(hasFileExtension, headers);
|
||||||
|
if (requestType !== EMBED) {
|
||||||
return handleShowRender(req, res);
|
return handleShowRender(req, res);
|
||||||
}
|
}
|
||||||
// handle serve request
|
|
||||||
// send google analytics
|
|
||||||
sendGAServeEvent(headers, ip, originalUrl);
|
|
||||||
// parse the claim
|
// parse the claim
|
||||||
let claimName;
|
let claimName;
|
||||||
try {
|
try {
|
||||||
|
@ -50,10 +47,10 @@ const serverAssetByIdentifierAndClaim = (req, res) => {
|
||||||
if (!isChannel) {
|
if (!isChannel) {
|
||||||
[claimId, claimName] = flipClaimNameAndId(claimId, claimName);
|
[claimId, claimName] = flipClaimNameAndId(claimId, claimName);
|
||||||
}
|
}
|
||||||
// log the request data for debugging
|
// send google analytics
|
||||||
logRequestData(responseType, claimName, channelName, claimId);
|
sendGAServeEvent(headers, ip, originalUrl);
|
||||||
// get the claim Id and then serve the asset
|
// get the claim Id and then serve the asset
|
||||||
getClaimIdAndServeAsset(channelName, channelClaimId, claimName, claimId, originalUrl, ip, res);
|
getClaimIdAndServeAsset(channelName, channelClaimId, claimName, claimId, originalUrl, ip, res);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = serverAssetByIdentifierAndClaim;
|
module.exports = serverByIdentifierAndClaim;
|
||||||
|
|
60
server/controllers/assets/utils/determineRequestType.js
Normal file
60
server/controllers/assets/utils/determineRequestType.js
Normal file
|
@ -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;
|
|
@ -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;
|
|
|
@ -17,7 +17,12 @@ const getClaimIdAndServeAsset = (channelName, channelClaimId, claimName, claimId
|
||||||
getClaimId(channelName, channelClaimId, claimName, claimId)
|
getClaimId(channelName, channelClaimId, claimName, claimId)
|
||||||
.then(fullClaimId => {
|
.then(fullClaimId => {
|
||||||
claimId = 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(() => {
|
.then(() => {
|
||||||
return getLocalFileRecord(claimId, claimName);
|
return getLocalFileRecord(claimId, claimName);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
const { details: { host } } = require('@config/siteConfig');
|
const { details: { host } } = require('@config/siteConfig');
|
||||||
|
|
||||||
const sendEmbedPage = ({ params }, res) => {
|
const sendVideoEmbedPage = ({ params }, res) => {
|
||||||
const claimId = params.claimId;
|
const claimId = params.claimId;
|
||||||
const name = params.name;
|
const name = params.name;
|
||||||
// get and render the content
|
// get and render the content
|
||||||
res.status(200).render('embed', { layout: 'embed', host, claimId, name });
|
res.status(200).render('embed', { layout: 'embed', host, claimId, name });
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = sendEmbedPage;
|
module.exports = sendVideoEmbedPage;
|
|
@ -1,6 +1,6 @@
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const { apiHost, apiPort } = require('@config/lbryConfig');
|
const { apiHost, apiPort, getTimeout } = require('@config/lbryConfig');
|
||||||
const lbrynetUri = 'http://' + apiHost + ':' + apiPort;
|
const lbrynetUri = 'http://' + apiHost + ':' + apiPort;
|
||||||
const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('../utils/googleAnalytics.js');
|
const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('../utils/googleAnalytics.js');
|
||||||
const handleLbrynetResponse = require('./utils/handleLbrynetResponse.js');
|
const handleLbrynetResponse = require('./utils/handleLbrynetResponse.js');
|
||||||
|
@ -31,7 +31,10 @@ module.exports = {
|
||||||
axios
|
axios
|
||||||
.post(lbrynetUri, {
|
.post(lbrynetUri, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { uri, timeout: 20 },
|
params: {
|
||||||
|
uri,
|
||||||
|
timeout: getTimeout || 30,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
sendGATimingEvent('lbrynet', 'getClaim', 'GET', gaStartTime, Date.now());
|
sendGATimingEvent('lbrynet', 'getClaim', 'GET', gaStartTime, Date.now());
|
||||||
|
|
31
server/middleware/torCheckMiddleware.js
Normal file
31
server/middleware/torCheckMiddleware.js
Normal file
|
@ -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;
|
|
@ -6,14 +6,6 @@ module.exports = (sequelize, { STRING }) => {
|
||||||
const Blocked = sequelize.define(
|
const Blocked = sequelize.define(
|
||||||
'Blocked',
|
'Blocked',
|
||||||
{
|
{
|
||||||
claimId: {
|
|
||||||
type : STRING,
|
|
||||||
allowNull: false,
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type : STRING,
|
|
||||||
allowNull: false,
|
|
||||||
},
|
|
||||||
outpoint: {
|
outpoint: {
|
||||||
type : STRING,
|
type : STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
@ -24,13 +16,12 @@ module.exports = (sequelize, { STRING }) => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Blocked.isNotBlocked = function (claimId, name) {
|
Blocked.isNotBlocked = function (outpoint) {
|
||||||
logger.debug(`checking to see if ${name}#${claimId} is not blocked`);
|
logger.debug(`checking to see if ${outpoint} is not blocked`);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.findOne({
|
this.findOne({
|
||||||
where: {
|
where: {
|
||||||
claimId,
|
outpoint,
|
||||||
name,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(result => {
|
.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;
|
return Blocked;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
return Claim;
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,7 @@ const File = require('./file.js');
|
||||||
const Request = require('./request.js');
|
const Request = require('./request.js');
|
||||||
const User = require('./user.js');
|
const User = require('./user.js');
|
||||||
const Blocked = require('./blocked.js');
|
const Blocked = require('./blocked.js');
|
||||||
|
const Tor = require('./tor.js');
|
||||||
|
|
||||||
const {database, username, password} = require('@config/mysqlConfig');
|
const {database, username, password} = require('@config/mysqlConfig');
|
||||||
if (!database || !username || !password) {
|
if (!database || !username || !password) {
|
||||||
|
@ -50,6 +51,7 @@ db['File'] = sequelize.import('File', File);
|
||||||
db['Request'] = sequelize.import('Request', Request);
|
db['Request'] = sequelize.import('Request', Request);
|
||||||
db['User'] = sequelize.import('User', User);
|
db['User'] = sequelize.import('User', User);
|
||||||
db['Blocked'] = sequelize.import('Blocked', Blocked);
|
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
|
// run model.association for each model in the db object that has an association
|
||||||
logger.info('associating db models...');
|
logger.info('associating db models...');
|
||||||
|
|
59
server/models/tor.js
Normal file
59
server/models/tor.js
Normal file
|
@ -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;
|
||||||
|
};
|
|
@ -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 channelAvailability = require('../../controllers/api/channel/availability');
|
||||||
const channelClaims = require('../../controllers/api/channel/claims');
|
const channelClaims = require('../../controllers/api/channel/claims');
|
||||||
const channelData = require('../../controllers/api/channel/data');
|
const channelData = require('../../controllers/api/channel/data');
|
||||||
const channelShortId = require('../../controllers/api/channel/shortId');
|
const channelShortId = require('../../controllers/api/channel/shortId');
|
||||||
const claimAvailability = require('../../controllers/api/claim/availability');
|
const claimAvailability = require('../../controllers/api/claim/availability');
|
||||||
const claimBlockedList = require('../../controllers/api/claim/blockedList');
|
|
||||||
const claimData = require('../../controllers/api/claim/data/');
|
const claimData = require('../../controllers/api/claim/data/');
|
||||||
const claimGet = require('../../controllers/api/claim/get');
|
const claimGet = require('../../controllers/api/claim/get');
|
||||||
const claimList = require('../../controllers/api/claim/list');
|
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 claimShortId = require('../../controllers/api/claim/shortId');
|
||||||
const fileAvailability = require('../../controllers/api/file/availability');
|
const fileAvailability = require('../../controllers/api/file/availability');
|
||||||
const userPassword = require('../../controllers/api/user/password');
|
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) => {
|
module.exports = (app) => {
|
||||||
// channel routes
|
// channel routes
|
||||||
app.get('/api/channel/availability/:name', channelAvailability);
|
app.get('/api/channel/availability/:name', torCheckMiddleware, channelAvailability);
|
||||||
app.get('/api/channel/short-id/:longId/:name', channelShortId);
|
app.get('/api/channel/short-id/:longId/:name', torCheckMiddleware, channelShortId);
|
||||||
app.get('/api/channel/data/:channelName/:channelClaimId', channelData);
|
app.get('/api/channel/data/:channelName/:channelClaimId', torCheckMiddleware, channelData);
|
||||||
app.get('/api/channel/claims/:channelName/:channelClaimId/:page', channelClaims);
|
app.get('/api/channel/claims/:channelName/:channelClaimId/:page', torCheckMiddleware, channelClaims);
|
||||||
// claim routes
|
// claim routes
|
||||||
app.get('/api/claim/availability/:name', claimAvailability);
|
app.get('/api/claim/availability/:name', torCheckMiddleware, claimAvailability);
|
||||||
app.get('/api/claim/blocked-list/', claimBlockedList);
|
app.get('/api/claim/data/:claimName/:claimId', torCheckMiddleware, claimData);
|
||||||
app.get('/api/claim/data/:claimName/:claimId', claimData);
|
app.get('/api/claim/get/:name/:claimId', torCheckMiddleware, claimGet);
|
||||||
app.get('/api/claim/get/:name/:claimId', claimGet);
|
app.get('/api/claim/list/:name', torCheckMiddleware, claimList);
|
||||||
app.get('/api/claim/list/:name', claimList);
|
app.post('/api/claim/long-id', torCheckMiddleware, claimLongId); // note: should be a 'get'
|
||||||
app.post('/api/claim/long-id', claimLongId);
|
app.post('/api/claim/publish', torCheckMiddleware, multipartMiddleware, claimPublish);
|
||||||
app.post('/api/claim/publish', multipartMiddleware, claimPublish);
|
app.get('/api/claim/resolve/:name/:claimId', torCheckMiddleware, claimResolve);
|
||||||
app.get('/api/claim/resolve/:name/:claimId', claimResolve);
|
app.get('/api/claim/short-id/:longId/:name', torCheckMiddleware, claimShortId);
|
||||||
app.get('/api/claim/short-id/:longId/:name', claimShortId);
|
|
||||||
// file routes
|
// file routes
|
||||||
app.get('/api/file/availability/:name/:claimId', fileAvailability);
|
app.get('/api/file/availability/:name/:claimId', torCheckMiddleware, fileAvailability);
|
||||||
// user routes
|
// 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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
const serveAssetByClaim = require('../../controllers/assets/serveByClaim');
|
const serveByClaim = require('../../controllers/assets/serveByClaim');
|
||||||
const serveAssetByIdentifierAndClaim = require('../../controllers/assets/serveByIdentifierAndClaim');
|
const serveByIdentifierAndClaim = require('../../controllers/assets/serveByIdentifierAndClaim');
|
||||||
|
const serveAsset = require('../../controllers/assets/serveAsset');
|
||||||
|
|
||||||
module.exports = (app, db) => {
|
module.exports = (app) => {
|
||||||
app.get('/:identifier/:claim', serveAssetByIdentifierAndClaim);
|
app.get('/asset/:claimName/:claimId/', serveAsset);
|
||||||
app.get('/:claim', serveAssetByClaim);
|
app.get('/:identifier/:claim', serveByIdentifierAndClaim);
|
||||||
|
app.get('/:claim', serveByClaim);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const handlePageRequest = require('../../controllers/pages/sendReactApp');
|
const handlePageRequest = require('../../controllers/pages/sendReactApp');
|
||||||
const handleEmbedRequest = require('../../controllers/pages/sendEmbedPage');
|
const handleVideoEmbedRequest = require('../../controllers/pages/sendVideoEmbedPage');
|
||||||
const redirect = require('../../controllers/utils/redirect');
|
const redirect = require('../../controllers/utils/redirect');
|
||||||
|
|
||||||
module.exports = (app) => {
|
module.exports = (app) => {
|
||||||
|
@ -10,5 +10,5 @@ module.exports = (app) => {
|
||||||
app.get('/popular', handlePageRequest);
|
app.get('/popular', handlePageRequest);
|
||||||
app.get('/new', handlePageRequest);
|
app.get('/new', handlePageRequest);
|
||||||
app.get('/multisite', 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
|
||||||
};
|
};
|
||||||
|
|
21
test/test.html
Normal file
21
test/test.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<img src="https://media.giphy.com/media/vwEHGjx71HSytx5mY8/giphy-facebook_s.jpg" alt="test embed"/>
|
||||||
|
<p>no identifier, no ending</p>
|
||||||
|
<img src="https://dev1.spee.ch/typingcat" alt="no identifier, no ending"/>
|
||||||
|
<p>no identifier, yes ending</p>
|
||||||
|
<img src="https://dev1.spee.ch/typingcat.gif" alt="no identifier, yes ending"/>
|
||||||
|
<p>yes identifier, no ending</p>
|
||||||
|
<img src="https://dev1.spee.ch/8/typingcat" alt="yes identifier, no ending"/>
|
||||||
|
<p>yes identifier, yes ending</p>
|
||||||
|
<img src="https://dev1.spee.ch/8/typingcat.gif" alt="yes identifier, yes ending"/>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue