From de4417b95431110b449f245b2064e782bfb4d8a4 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Sun, 8 Nov 2020 20:24:30 +0800 Subject: [PATCH] feat: support qiniu kudo --- src/api/file.js | 51 ++++++ src/assets/scripts/tokenTools.js | 155 ++++++++++++++++++ .../CodemirrorEditor/uploadImgDialog.vue | 95 +++++++++++ 3 files changed, 301 insertions(+) create mode 100644 src/assets/scripts/tokenTools.js diff --git a/src/api/file.js b/src/api/file.js index ba74498..a9196f2 100644 --- a/src/api/file.js +++ b/src/api/file.js @@ -1,8 +1,11 @@ import fetch from "./fetch"; +import CryptoJS from "crypto-js"; import OSS from "ali-oss"; import COS from "cos-js-sdk-v5"; import Buffer from "buffer-from"; import { v4 as uuidv4 } from "uuid"; +import * as qiniu from "qiniu-js"; +import { utf16to8, base64encode, safe64 } from "../assets/scripts/tokenTools"; const defaultConfig = { username: "filess", @@ -28,6 +31,8 @@ function fileUpload(content, file) { return aliOSSFileUpload(content, file.name); case "txCOS": return txCOSFileUpload(file); + case "qiniu": + return qiniuUpload(file); case "github": default: return ghFileUpload(content, file.name); @@ -81,6 +86,14 @@ function getGitHubConfig() { ); } +function getQiniuToken(accessKey, secretKey, putPolicy) { + const policy = JSON.stringify(putPolicy); + const encoded = base64encode(utf16to8(policy)); + const hash = CryptoJS.HmacSHA1(encoded, secretKey); + const encodedSigned = hash.toString(CryptoJS.enc.Base64); + return accessKey + ":" + safe64(encodedSigned) + ":" + encoded; +} + async function ghFileUpload(content, filename) { const isDefault = localStorage.getItem("imgHost") !== "github"; const config = isDefault ? getDefaultConfig() : getGitHubConfig(); @@ -166,6 +179,44 @@ async function txCOSFileUpload(file) { }); } +async function qiniuUpload(file) { + const qiniuConfig = JSON.parse(localStorage.getItem("qiniuConfig")); + const putPolicy = { + scope: qiniuConfig.bucket, + deadline: Math.trunc(new Date().getTime() / 1000) + 3600, + }; + const token = getQiniuToken( + qiniuConfig.accessKey, + qiniuConfig.secretKey, + putPolicy + ); + const dir = qiniuConfig.path ? qiniuConfig.path + "/" : ""; + const dateFilename = + dir + + new Date().getTime() + + "-" + + uuidv4() + + "." + + file.name.split(".")[1]; + const config = { + region: qiniuConfig.region, + }; + const observable = qiniu.upload(file, dateFilename, token, {}, config); + return new Promise((resolve, reject) => { + observable.subscribe({ + next: (result) => { + console.log(result); + }, + error: (err) => { + reject(err.message); + }, + complete: (result) => { + resolve(qiniuConfig.domain + "/" + result.key); + }, + }); + }); +} + export default { fileUpload, }; diff --git a/src/assets/scripts/tokenTools.js b/src/assets/scripts/tokenTools.js new file mode 100644 index 0000000..d7868b7 --- /dev/null +++ b/src/assets/scripts/tokenTools.js @@ -0,0 +1,155 @@ +/* utf.js - UTF-8 <=> UTF-16 convertion + * + * Copyright (C) 1999 Masanao Izumo + * Version: 1.0 + * LastModified: Dec 25 1999 + * This library is free. You can redistribute it and/or modify it. + */ +/* + * Interfaces: + * utf8 = utf16to8(utf16); + * utf16 = utf8to16(utf8); + */ + +export function utf16to8(str) { + var out, i, len, c; + out = ""; + len = str.length; + for (i = 0; i < len; i++) { + c = str.charCodeAt(i); + if ((c >= 0x0001) && (c <= 0x007F)) { + out += str.charAt(i); + } else if (c > 0x07FF) { + out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); + out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); + out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); + } else { + out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); + out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); + } + } + return out; +} + +export function utf8to16(str) { + var out, i, len, c; + var char2, char3; + out = ""; + len = str.length; + i = 0; + while (i < len) { + c = str.charCodeAt(i++); + switch (c >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + // 0xxxxxxx + out += str.charAt(i - 1); + break; + case 12: + case 13: + // 110x xxxx 10xx xxxx + char2 = str.charCodeAt(i++); + out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); + break; + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + char2 = str.charCodeAt(i++); + char3 = str.charCodeAt(i++); + out += String.fromCharCode(((c & 0x0F) << 12) + | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); + break; + } + } + return out; +} +//======================================================== +/* + * Interfaces: + * b64 = base64encode(data); + * data = base64decode(b64); + */ +var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; +var base64DecodeChars = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1); +export function base64encode(str) { + var out, i, len; + var c1, c2, c3; + len = str.length; + i = 0; + out = ""; + while (i < len) { + c1 = str.charCodeAt(i++) & 0xff; + if (i == len) { + out += base64EncodeChars.charAt(c1 >> 2); + out += base64EncodeChars.charAt((c1 & 0x3) << 4); + out += "=="; + break; + } + c2 = str.charCodeAt(i++); + if (i == len) { + out += base64EncodeChars.charAt(c1 >> 2); + out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); + out += base64EncodeChars.charAt((c2 & 0xF) << 2); + out += "="; + break; + } + c3 = str.charCodeAt(i++); + out += base64EncodeChars.charAt(c1 >> 2); + out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); + out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)); + out += base64EncodeChars.charAt(c3 & 0x3F); + } + return out; +} + +export function base64decode(str) { + var c1, c2, c3, c4; + var i, len, out; + len = str.length; + i = 0; + out = ""; + while (i < len) { + /* c1 */ + do { + c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff]; + } while (i < len && c1 == -1); + if (c1 == -1) break; + /* c2 */ + do { + c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff]; + } while (i < len && c2 == -1); + if (c2 == -1) break; + out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); + /* c3 */ + do { + c3 = str.charCodeAt(i++) & 0xff; + if (c3 == 61) return out; + c3 = base64DecodeChars[c3]; + } while (i < len && c3 == -1); + if (c3 == -1) break; + out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)); + /* c4 */ + do { + c4 = str.charCodeAt(i++) & 0xff; + if (c4 == 61) return out; + c4 = base64DecodeChars[c4]; + } while (i < len && c4 == -1); + if (c4 == -1) break; + out += String.fromCharCode(((c3 & 0x03) << 6) | c4); + } + return out; +} + +export function safe64(base64) { + base64 = base64.replace(/\+/g, "-"); + base64 = base64.replace(/\//g, "_"); + return base64; +} \ No newline at end of file diff --git a/src/components/CodemirrorEditor/uploadImgDialog.vue b/src/components/CodemirrorEditor/uploadImgDialog.vue index d57ee6c..9be7dcb 100644 --- a/src/components/CodemirrorEditor/uploadImgDialog.vue +++ b/src/components/CodemirrorEditor/uploadImgDialog.vue @@ -201,6 +201,66 @@ + + + + + + + + + + + + + + + + + + + + 如何使用七牛云 Kodo? + + + 保存配置 + + + @@ -238,6 +298,13 @@ export default { path: "", cdnHost: "", }, + formQiniu: { + accessKey: "", + secretKey: "", + bucket: "", + domain: "", + region: "", + }, options: [ { value: "default", @@ -255,6 +322,10 @@ export default { value: "txCOS", label: "腾讯云", }, + { + value: "qiniu", + label: "七牛云", + }, ], imgHost: "default", uploadingImg: false, @@ -353,6 +424,30 @@ export default { }); }, + saveQiniuConfiguration() { + if ( + !( + this.formQiniu.accessKey && + this.formQiniu.secretKey && + this.formQiniu.bucket && + this.formQiniu.domain && + this.formQiniu.region + ) + ) { + this.$message({ + showClose: true, + message: `七牛云 Kodo 参数配置不全`, + type: "error", + }); + return; + } + localStorage.setItem("qiniuConfig", JSON.stringify(this.formQiniu)); + this.$message({ + message: "保存成功", + type: "success", + }); + }, + // 图片上传前的处理 beforeUpload(file) { if (!this.validateConfig()) {