* Added an API endpoint to check the existence of the file * fix #2773: Now we can prevent users from posting the same images * bug fix
This commit is contained in:
		
							parent
							
								
									d0570d7fe3
								
							
						
					
					
						commit
						3e897727ca
					
				
					 3 changed files with 106 additions and 34 deletions
				
			
		
							
								
								
									
										8
									
								
								src/client/app/common/scripts/get-md5.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/app/common/scripts/get-md5.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					const crypto = require('crypto');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default (data: ArrayBuffer) => {
 | 
				
			||||||
 | 
					  const buf = new Buffer(data);
 | 
				
			||||||
 | 
					  const hash = crypto.createHash("md5");
 | 
				
			||||||
 | 
					  hash.update(buf);
 | 
				
			||||||
 | 
					  return hash.digest("hex");
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
import Vue from 'vue';
 | 
					import Vue from 'vue';
 | 
				
			||||||
import { apiUrl } from '../../../config';
 | 
					import { apiUrl } from '../../../config';
 | 
				
			||||||
 | 
					import getMD5 from '../../scripts/get-md5';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Vue.extend({
 | 
					export default Vue.extend({
 | 
				
			||||||
	data() {
 | 
						data() {
 | 
				
			||||||
| 
						 | 
					@ -28,53 +29,78 @@ export default Vue.extend({
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		upload(file, folder) {
 | 
							checkExistence(fileData: ArrayBuffer): Promise<any> {
 | 
				
			||||||
 | 
								return new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
									const data = new FormData();
 | 
				
			||||||
 | 
									data.append('md5', getMD5(fileData));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									(this as any).api('drive/files/check_existence', {
 | 
				
			||||||
 | 
										md5: getMD5(fileData)
 | 
				
			||||||
 | 
									}).then(resp => {
 | 
				
			||||||
 | 
										resolve(resp.file);
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							upload(file: File, folder: any) {
 | 
				
			||||||
			if (folder && typeof folder == 'object') folder = folder.id;
 | 
								if (folder && typeof folder == 'object') folder = folder.id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			const id = Math.random();
 | 
								const id = Math.random();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			const ctx = {
 | 
					 | 
				
			||||||
				id: id,
 | 
					 | 
				
			||||||
				name: file.name || 'untitled',
 | 
					 | 
				
			||||||
				progress: undefined,
 | 
					 | 
				
			||||||
				img: undefined
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			this.uploads.push(ctx);
 | 
					 | 
				
			||||||
			this.$emit('change', this.uploads);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			const reader = new FileReader();
 | 
								const reader = new FileReader();
 | 
				
			||||||
			reader.onload = (e: any) => {
 | 
								reader.onload = (e: any) => {
 | 
				
			||||||
				ctx.img = e.target.result;
 | 
									this.checkExistence(e.target.result).then(result => {
 | 
				
			||||||
			};
 | 
										console.log(result);
 | 
				
			||||||
			reader.readAsDataURL(file);
 | 
										if (result !== null) {
 | 
				
			||||||
 | 
											this.$emit('uploaded', result);
 | 
				
			||||||
 | 
											return;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			const data = new FormData();
 | 
										// Upload if the file didn't exist yet
 | 
				
			||||||
			data.append('i', this.$store.state.i.token);
 | 
										const buf = new Uint8Array(e.target.result);
 | 
				
			||||||
			data.append('file', file);
 | 
										let bin = "";
 | 
				
			||||||
 | 
										// We use for-of loop instead of apply() to avoid RangeError
 | 
				
			||||||
 | 
										// SEE: https://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string
 | 
				
			||||||
 | 
										for (const byte of buf) bin += String.fromCharCode(byte);
 | 
				
			||||||
 | 
										const ctx = {
 | 
				
			||||||
 | 
											id: id,
 | 
				
			||||||
 | 
											name: file.name || 'untitled',
 | 
				
			||||||
 | 
											progress: undefined,
 | 
				
			||||||
 | 
											img: 'data:*/*;base64,' + btoa(bin)
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (folder) data.append('folderId', folder);
 | 
										this.uploads.push(ctx);
 | 
				
			||||||
 | 
										this.$emit('change', this.uploads);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			const xhr = new XMLHttpRequest();
 | 
										const data = new FormData();
 | 
				
			||||||
			xhr.open('POST', apiUrl + '/drive/files/create', true);
 | 
										data.append('i', this.$store.state.i.token);
 | 
				
			||||||
			xhr.onload = (e: any) => {
 | 
										data.append('file', file);
 | 
				
			||||||
				const driveFile = JSON.parse(e.target.response);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				this.$emit('uploaded', driveFile);
 | 
										if (folder) data.append('folderId', folder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				this.uploads = this.uploads.filter(x => x.id != id);
 | 
										const xhr = new XMLHttpRequest();
 | 
				
			||||||
				this.$emit('change', this.uploads);
 | 
										xhr.open('POST', apiUrl + '/drive/files/create', true);
 | 
				
			||||||
			};
 | 
										xhr.onload = (e: any) => {
 | 
				
			||||||
 | 
											const driveFile = JSON.parse(e.target.response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			xhr.upload.onprogress = e => {
 | 
											this.$emit('uploaded', driveFile);
 | 
				
			||||||
				if (e.lengthComputable) {
 | 
					 | 
				
			||||||
					if (ctx.progress == undefined) ctx.progress = {};
 | 
					 | 
				
			||||||
					ctx.progress.max = e.total;
 | 
					 | 
				
			||||||
					ctx.progress.value = e.loaded;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			xhr.send(data);
 | 
											this.uploads = this.uploads.filter(x => x.id != id);
 | 
				
			||||||
 | 
											this.$emit('change', this.uploads);
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										xhr.upload.onprogress = e => {
 | 
				
			||||||
 | 
											if (e.lengthComputable) {
 | 
				
			||||||
 | 
												if (ctx.progress == undefined) ctx.progress = {};
 | 
				
			||||||
 | 
												ctx.progress.max = e.total;
 | 
				
			||||||
 | 
												ctx.progress.value = e.loaded;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										xhr.send(data);
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								reader.readAsArrayBuffer(file);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/server/api/endpoints/drive/files/check_existence.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/server/api/endpoints/drive/files/check_existence.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					import $ from 'cafy';
 | 
				
			||||||
 | 
					import DriveFile, { pack } from '../../../../../models/drive-file';
 | 
				
			||||||
 | 
					import { ILocalUser } from '../../../../../models/user';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const meta = {
 | 
				
			||||||
 | 
						desc: {
 | 
				
			||||||
 | 
							'ja-JP': '与えられたMD5ハッシュ値を持つファイルがドライブに存在するかどうかを返します。',
 | 
				
			||||||
 | 
							'en-US': 'Returns whether the file with the given MD5 hash exists in the user\'s drive.'
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						requireCredential: true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kind: 'drive-read',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						params: {
 | 
				
			||||||
 | 
							md5: $.str.note({
 | 
				
			||||||
 | 
								desc: {
 | 
				
			||||||
 | 
									'ja-JP': 'ファイルのMD5ハッシュ'
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
 | 
				
			||||||
 | 
						const [md5, md5Err] = $.str.get(params.md5);
 | 
				
			||||||
 | 
						if (md5Err) return rej('invalid md5 param');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const file = await DriveFile.findOne({
 | 
				
			||||||
 | 
							md5: md5,
 | 
				
			||||||
 | 
							'metadata.userId': user._id
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (file === null) {
 | 
				
			||||||
 | 
							res({ file: null });
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							res({ file: await pack(file) });
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue