From 34772fa1b6b7d4ecb5b83a47c45b5dbdff6e7070 Mon Sep 17 00:00:00 2001 From: Vyrtsev Mikhail Date: Mon, 15 Apr 2019 08:26:09 +0300 Subject: [PATCH] deny anonymous image upload --- web/app/components/comment/comment.tsx | 8 +++-- web/app/components/input/input.tsx | 23 ++++++++------- web/app/components/root/root.tsx | 11 ++++++- web/app/utils/isUserAnonymous.ts | 8 +++++ web/package-lock.json | 41 +++++++++++++++++++------- 5 files changed, 65 insertions(+), 26 deletions(-) create mode 100644 web/app/utils/isUserAnonymous.ts diff --git a/web/app/components/comment/comment.tsx b/web/app/components/comment/comment.tsx index d27e80af..392c2eb1 100644 --- a/web/app/components/comment/comment.tsx +++ b/web/app/components/comment/comment.tsx @@ -13,6 +13,7 @@ import debounce from '@app/utils/debounce'; import copy from '@app/common/copy'; import { Theme, BlockTTL, Comment as CommentType, PostInfo, User, CommentMode, Image } from '@app/common/types'; import { extractErrorMessageFromResponse, FetcherError } from '@app/utils/errorUtils'; +import { isUserAnonymous } from '@app/utils/isUserAnonymous'; import { Input } from '@app/components/input'; import { AvatarIcon } from '@app/components/avatar-icon'; @@ -315,7 +316,7 @@ export class Comment extends Component { * Defines whether current client is logged in via `Anonymous provider` */ isAnonymous(): boolean { - return this.props.user! && this.props.user!.id.substr(0, 10) === 'anonymous_'; + return isUserAnonymous(this.props.user); } /** @@ -369,6 +370,7 @@ export class Comment extends Component { const isUpvotingDisabled = upvotingDisabledReason !== null; const editable = props.repliesCount === 0 && state.editDeadline; const scoreSignEnabled = !StaticStore.config.positive_score; + const uploadImageHandler = this.isAnonymous() ? undefined : this.props.uploadImage; /** * CommentType adapted for rendering @@ -676,7 +678,7 @@ export class Comment extends Component { onCancel={this.toggleReplying} getPreview={this.props.getPreview!} autofocus={true} - uploadImage={this.props.uploadImage!} + uploadImage={uploadImageHandler} /> )} @@ -691,7 +693,7 @@ export class Comment extends Component { getPreview={this.props.getPreview!} errorMessage={state.editDeadline === null ? 'Editing time has expired.' : undefined} autofocus={true} - uploadImage={this.props.uploadImage!} + uploadImage={uploadImageHandler} /> )} diff --git a/web/app/components/input/input.tsx b/web/app/components/input/input.tsx index e669be04..158982e8 100644 --- a/web/app/components/input/input.tsx +++ b/web/app/components/input/input.tsx @@ -38,7 +38,7 @@ interface Props { getPreview(text: string): Promise; /** action on cancel. optional as root input has no cancel option */ onCancel?: () => void; - uploadImage: (image: File) => Promise; + uploadImage?: (image: File) => Promise; } interface State { @@ -194,6 +194,7 @@ export class Input extends Component { } onDragOver(e: DragEvent) { + if (!this.props.uploadImage) return; if (StaticStore.config.max_image_size === 0) return; if (!this.textAreaRef) return; if (!e.dataTransfer) return; @@ -204,6 +205,7 @@ export class Input extends Component { } onDrop(e: DragEvent) { + if (!this.props.uploadImage) return; if (StaticStore.config.max_image_size === 0) return; if (!e.dataTransfer) return; @@ -217,20 +219,19 @@ export class Input extends Component { /** wrapper with error handling for props.uploadImage */ uploadImage(file: File): Promise { - return this.props - .uploadImage(file) - .catch( - (e: ApiError | string) => - new Error( - typeof e === 'string' - ? `${file.name} upload failed with "${e}"` - : `${file.name} upload failed with "${e.error}"` - ) - ); + return this.props.uploadImage!(file).catch( + (e: ApiError | string) => + new Error( + typeof e === 'string' + ? `${file.name} upload failed with "${e}"` + : `${file.name} upload failed with "${e.error}"` + ) + ); } /** performs upload process */ async uploadImages(files: File[]) { + if (!this.props.uploadImage) return; if (!this.textAreaRef) return; /** Human readable image size limit, i.e 5MB */ diff --git a/web/app/components/root/root.tsx b/web/app/components/root/root.tsx index 568822bb..9c41d3d1 100644 --- a/web/app/components/root/root.tsx +++ b/web/app/components/root/root.tsx @@ -49,6 +49,7 @@ import { Input } from '@app/components/input'; import Preloader from '@app/components/preloader'; import { Thread } from '@app/components/thread'; import { uploadImage } from '@app/common/api'; +import { isUserAnonymous } from '@app/utils/isUserAnonymous'; interface Props { user: User | null; @@ -192,6 +193,13 @@ export class Root extends Component { }); } + /** + * Defines whether current client is logged in via `Anonymous provider` + */ + isAnonymous(): boolean { + return isUserAnonymous(this.props.user); + } + render(props: RenderableProps, { isLoaded, isCommentsListLoading, commentsShown }: State) { if (!isLoaded) { return ( @@ -205,6 +213,7 @@ export class Root extends Component { const isGuest = !props.user; const isCommentsDisabled = !!props.info.read_only; + const imageUploadHandler = this.isAnonymous() ? undefined : this.props.uploadImage; return (
@@ -235,7 +244,7 @@ export class Root extends Component { userId={this.props.user!.id} onSubmit={(text, title) => this.props.addComment(text, title)} getPreview={this.props.getPreview} - uploadImage={this.props.uploadImage} + uploadImage={imageUploadHandler} /> )} diff --git a/web/app/utils/isUserAnonymous.ts b/web/app/utils/isUserAnonymous.ts new file mode 100644 index 00000000..e64aa9e6 --- /dev/null +++ b/web/app/utils/isUserAnonymous.ts @@ -0,0 +1,8 @@ +import { User } from '@app/common/types'; + +/** + * Defines whether current client is logged in via `Anonymous provider` + */ +export function isUserAnonymous(user?: User | null): boolean { + return user! && user!.id.substr(0, 10) === 'anonymous_'; +} diff --git a/web/package-lock.json b/web/package-lock.json index d6838b69..324d49c8 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -4854,7 +4854,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -4875,12 +4876,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4895,17 +4898,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5022,7 +5028,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5034,6 +5041,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5048,6 +5056,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5055,12 +5064,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5079,6 +5090,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5159,7 +5171,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5171,6 +5184,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5256,7 +5270,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -5292,6 +5307,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5311,6 +5327,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5354,12 +5371,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } },