diff --git a/package.json b/package.json index 06efb07..06c2a13 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,12 @@ }, "dependencies": { "axios": "^0.27.2", + "bluebird": "^3.7.2", "clipboard": "^2.0.11", "crypto-js": "^4.1.1", "escape-html": "^1.0.3", "file-saver": "^2.0.5", + "localforage": "^1.10.0", "pako": "^2.1.0", "qrcodejs2": "^0.0.2", "view-design": "^4.7.0", diff --git a/public/redirect.html b/public/redirect.html new file mode 100644 index 0000000..0407f57 --- /dev/null +++ b/public/redirect.html @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + flagnote.com + + + + + + + + \ No newline at end of file diff --git a/src/api/note.js b/src/api/note.js index e046c94..a42f225 100644 --- a/src/api/note.js +++ b/src/api/note.js @@ -1,7 +1,7 @@ import axios from "axios"; import { getStoreKey } from "@/api/lock"; import storage from "@/libs/storage"; -import { md5, wrap} from "@/libs/secret"; +import { md5, wrap } from "@/libs/secret"; import NoteConstant from "@/libs/constants"; axios.interceptors.response.use(undefined, (err) => { @@ -17,10 +17,10 @@ axios.interceptors.response.use(undefined, (err) => { } }); -export function saveNote(noteForm, secret) { +export async function saveNote(noteForm, secret) { let storeKey = secret.storeKey; - let storeInfo = storage.local.getText(storeKey); + const storeInfo = await storage.local.getText(storeKey); let starray = storeInfo.split("|"); if (starray[2] == "1") { @@ -71,14 +71,13 @@ export function saveNote(noteForm, secret) { }); } -export function deleteNote(key) { +export async function deleteNote(key) { let storeKey = getStoreKey(key); - let storeInfo = storage.local.getText(storeKey); + const storeInfo = await storage.local.getText(storeKey); let note = { cipher: storeInfo.substring(2, 34), key: key, }; - return axios({ url: NoteConstant.servicePath + "/note/" + key + "/delete", method: "post", @@ -97,6 +96,28 @@ export function getNoteBlob(key) { }); } +export function getNoteMetaNew(key) { + let url = NoteConstant.servicePath + "/note/" + key + "/noteMeta"; + return axios({ + url: url, + method: "get", + ignoreError: 1, + original: true, + source: true, + }); +} + +export function getKeyMetaNew() { + let url = NoteConstant.servicePath + "/note/keyMeta"; + return axios({ + url: url, + method: "get", + ignoreError: 1, + original: true, + source: true, + }); +} + export function getNoteMeta(key) { let url = NoteConstant.servicePath + "/note/" + key + "/noteMeta"; let noteMeta = null; @@ -137,4 +158,4 @@ export function ajaxGet(url) { }; xmlhttp.send(); return data; -} +} \ No newline at end of file diff --git a/src/libs/page.js b/src/libs/page.js new file mode 100644 index 0000000..e426280 --- /dev/null +++ b/src/libs/page.js @@ -0,0 +1,197 @@ +import { getStoreKey } from "@/api/lock"; +import storage from "@/libs/storage"; +import { getNoteMetaNew, getNoteBlob } from "@/api/note"; +import { reject } from "bluebird"; +import { unwrap, md5 } from '@/libs/secret' + + +export async function initPageData(view) { + + let noteKey = view.noteForm.key; + + let storeKey = getStoreKey(noteKey); + view.secret.storeKey = storeKey; + + let keyMeta = storage.session.getObject("keyMeta"); + if (keyMeta) { + view.state.lock = 0; + view.secret.cipher = keyMeta.cipher; + view.secret.secretKey = keyMeta.secretKey; + view.state.serverTime = keyMeta.serverTime; + // key init Time + view.state.initTime = keyMeta.serverTime; + + await storage.local.setText(storeKey, "0|" + view.secret.cipher + "|0|" + view.state.initTime + "|"); + storage.session.delete("keyMeta"); + return "000000"; + } + + let noteMeta = storage.session.getObject(noteKey+".noteMeta"); + + if(null==noteMeta){ + let resp = await getNoteMetaNew(view.noteForm.key); + if (null == resp || null == resp.data) { + return "100006"; + } + let result = resp.data; + if (result.code != '000000') { + return result.code; + } + let noteMeta = result.data; + if (null == noteMeta) { + return "100001"; + } + if (null == noteMeta.key) { + return "100002"; + } + storage.session.setObject(noteKey+".noteMeta",noteMeta); + }else{ + getNoteMetaNew(view.noteForm.key).then(function(resp){ + if (null == resp || null == resp.data) { + return "100006"; + } + let result = resp.data; + if (result.code != '000000') { + return result.code; + } + let noteMeta = result.data; + if (null == noteMeta) { + return "100001"; + } + if (null == noteMeta.key) { + return "100002"; + } + }); + } + + //view + if (1 == noteMeta.state) { + + view.secret.secretKey = noteMeta.secretKey; + + view.state.lock = noteMeta.lock; + view.state.initTime = new Date().getTime(); + view.state.initTtl = noteMeta.ttl; + view.state.ttl = noteMeta.ttl; + view.state.serverTime = noteMeta.serverTime; + + view.secret.cipher = "00000000000000000000000000000000";//noteMeta.cipher; //读者有没有值可配置 + view.secret.md5 = noteMeta.md5; + + await loadText(view); + return "000000"; + } + + //deleted + if (0 == noteMeta.state) { + let storeKey = getStoreKey(noteKey); + storage.local.delete(storeKey); + // user deleted + if (noteMeta.ttl > 0) { + // errorMeta = 100003; + return "100003"; + //return errorRouter(100003); + } else {// timeout + // errorMeta = 100004; + return "100004"; + //return errorRouter(100004); + } + } + + //edit or unsubmitted + if (null == noteMeta.state) { + let storeKey = getStoreKey(noteKey); + const storeInfo = await storage.local.getText(storeKey); + + //if has storage , then edit + if (null != storeInfo) { + view.secret.secretKey = noteMeta.secretKey; + + let starray = storeInfo.split('|'); + view.state.lock = parseInt(starray[0]); + view.secret.cipher = starray[1]; + view.state.initTime = parseInt(starray[3]); + //draw text; + if (starray[4]) { + view.noteForm.text = unwrap(starray[4], view.secret.secretKey); + } + + return "000000"; + } + + //storage is empty + let df = storage.session.getText(storeKey + "_delete") + if (df) {//unsubmitted,user deleted. + // errorMeta = 100003; + return "100003"; + } else {//unsubmitted + // errorMeta = 100005; + return "100005"; + } + } + + +} + +async function loadText(view) { + + let storeInfo = await storage.local.getText(view.secret.storeKey); + + let starray = []; + if (storeInfo) { + starray = storeInfo.split('|'); + } + + if (!storeInfo || !starray[4] || (md5(starray[4]) != view.secret.md5)) { + + let bytesString = await getServerNote(view.noteForm.key); + view.noteForm.text = unwrap(bytesString, view.secret.secretKey); + } else { + starray = storeInfo.split('|'); + + if (!starray[4]) { + return; + } + + view.noteForm.text = unwrap(starray[4], view.secret.secretKey); + //this.noteForm.escapeText = getEscapeText(this.noteForm.text); + + // local is usable, and set commited flag + if ("0" == starray[2]) { + storage.local.setText(this.secret.storeKey, starray[0] + "|" + starray[1] + "|1|" + starray[3] + "|" + starray[4]); + } + } +} + +async function getServerNote(key) { + let resp = await getNoteBlob(key) + if (!resp.data || resp.data.size == 0) { + return "100006"; + } + + let blob = new Blob([resp.data], { + type: resp.data.type + }); + + let bytesString = await fileReader(blob); + + return bytesString; + + +} + +async function fileReader(blob) { + return new Promise(function (resolve) { + let reader = new FileReader(); + reader.onload = function (e) { + if (!e.target.result || e.target.result.byteLength == 0) { + reject(""); + } + var bytes = new Uint8Array(e.target.result); + bytes = bytes.subarray(7, bytes.length - 7); + let bytesString = bytes.join(","); + resolve(bytesString); + }; + reader.readAsArrayBuffer(blob) + }); +} \ No newline at end of file diff --git a/src/libs/storage.js b/src/libs/storage.js index 2d9ce6d..66564cd 100644 --- a/src/libs/storage.js +++ b/src/libs/storage.js @@ -1,3 +1,5 @@ +import localforage from "localforage"; + class Storage { constructor() { this.session = new Session(); @@ -29,23 +31,23 @@ class Session { class Local { setObject(key, value) { - localStorage.setItem(key, JSON.stringify(value)); + return localforage.setItem(key, JSON.stringify(value)); } getObject(key) { - return JSON.parse(localStorage.getItem(key)); + return JSON.parse(localforage.getItem(key)); } delete(key) { - localStorage.removeItem(key); + return localforage.removeItem(key); } setText(key, value) { - localStorage.setItem(key, value); + return localforage.setItem(key, value); } getText(key) { - return localStorage.getItem(key); + return localforage.getItem(key); } getUseSize() { @@ -129,4 +131,4 @@ class Local { } const storage = new Storage(); -export default storage; +export default storage; \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index 74c425c..bed69a1 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,144 +1,17 @@ import Vue from "vue"; import VueRouter from "vue-router"; -import EditNote from "@/views/EditNote.vue"; -import ViewNote from "@/views/ViewNote.vue"; -import ErrorRoute from "@/views/ErrorRoute.vue"; -import ErrorNote from "@/views/ErrorNote.vue"; -import { getKeyMeta, getNoteMeta } from "@/api/note"; -import { getStoreKey } from "@/api/lock"; -import storage from "@/libs/storage"; +import NoteView from "@/views/NoteView.vue"; +import ErrorView from "@/views/ErrorView.vue"; Vue.use(VueRouter); -var keyMeta = null; -var noteMeta = null; -var errorMeta = null; - -function getKeyMetaParam() { - return keyMeta; -} - -function getNoteMetaParam() { - return noteMeta; -} - -function getErrorMetaParam() { - return errorMeta; -} - -function getNoteView() { - if (errorMeta) { - return; - } - - let path = location.pathname; - - let key = path.substring(1, path.length); - - if (keyMeta && keyMeta.key) { - key = keyMeta.key; - } - - let regKey = /^[abcdefhikmnopqstuvwxyz23456789]{16}$/; - if (!regKey.test(key)) { - errorMeta = 100002; - return ErrorNote; - } - - if (keyMeta && keyMeta.key) { - //firstEdit - return EditNote; - } - - //set noteMeta - noteMeta = getNoteMeta(key); - - //server error - if (!noteMeta) { - errorMeta = 100006; - return ErrorNote; - } - - //invalidated key - if (!noteMeta.key) { - errorMeta = 100002; - return ErrorNote; - } - - //validated state - if (1 == noteMeta.state) { - return ViewNote; - } - - //deleted - if (0 == noteMeta.state) { - let storeKey = getStoreKey(key); - storage.local.delete(storeKey); - // user deleted - if (noteMeta.ttl > 0) { - errorMeta = 100003; - return ErrorNote; - } else {// timeout - errorMeta = 100004; - return ErrorNote; - } - } - - if (null == noteMeta.state) { - let storeKey = getStoreKey(key); - //if has storage , then edit - if (storage.local.getText(storeKey)) { - return EditNote; - } else { - //storage is empty - let df = storage.session.getText(storeKey + "_delete") - if (df) {//unsubmitted,user deleted. - errorMeta = 100003; - return ErrorNote; - } else {//unsubmitted - errorMeta = 100005; - return ErrorNote; - } - } - } - - // other exception - errorMeta = 100001; - return ErrorNote; -} - -function getHomeRedirect() { - let path = location.pathname; - if (path != "/") { - return; - } - - //setKeyMeta - keyMeta = getKeyMeta(); - - // server error - if (!keyMeta) { - errorMeta = 100006; - return "/error_"+errorMeta; - } - - return "/" + keyMeta.key; -} - const routes = [ { - path: "/", - name: "home", - redirect: getHomeRedirect(), - }, - { path: "/error_:code([0-9]{6})", component: ErrorNote }, - { - path: "/:name([a-z0-9]{10,20})", + path: "/:name([abcdefhikmnopqstuvwxyz23456789]{16})", name: "note", - component: getNoteView(), - meta: { keyMeta: getKeyMetaParam(), noteMeta: getNoteMetaParam(), errorMeta: getErrorMetaParam() }, + component: NoteView, }, - { path: "/:path(.*)", component: ErrorRoute } + { path: "/:path(.*)", component: ErrorView } ]; const router = new VueRouter({ diff --git a/src/views/ErrorRoute.vue b/src/views/ErrorView.vue similarity index 91% rename from src/views/ErrorRoute.vue rename to src/views/ErrorView.vue index 70f2502..7a97afc 100644 --- a/src/views/ErrorRoute.vue +++ b/src/views/ErrorView.vue @@ -6,7 +6,7 @@ diff --git a/vue.config.js b/vue.config.js index f24bc72..e9e9663 100644 --- a/vue.config.js +++ b/vue.config.js @@ -65,8 +65,8 @@ module.exports = defineConfig({ devServer: { proxy: { "/note": { -// target: "https://flagnote.com/", // 后台接口域名 - target: "http://localhost:10000/", // 后台接口域名 + target: "https://flagnote.com/", // 后台接口域名 +// target: "http://localhost:10000/", // 后台接口域名 secure: false, // 如果是https接口,需要配置这个参数 changeOrigin: true, //是否跨域 pathRewrite: { diff --git a/yarn.lock b/yarn.lock index 9e63f41..ebaca6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2047,7 +2047,7 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -bluebird@^3.1.1: +bluebird@^3.1.1, bluebird@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -3743,6 +3743,11 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.1.tgz#c2b1f76cb999ede1502f3a226a9310fdfe88d46c" integrity sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -4145,6 +4150,13 @@ libphonenumber-js@^1.9.43: resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.14.tgz#e29da7f539751f724ac54017a098e3c7ca23de94" integrity sha512-McGS7GV/WjJ2KjfOGhJU1oJn29RYeo7Q+RpANRbUNMQ9gj5XArpbjurSuyYPTejFwbaUojstQ4XyWCrAzGOUXw== +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" + lilconfig@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" @@ -4178,6 +4190,13 @@ loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" +localforage@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== + dependencies: + lie "3.1.1" + locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -6204,7 +6223,7 @@ vue-loader@^17.0.0: hash-sum "^2.0.0" loader-utils "^2.0.0" -vue-router@^3.5.4: +vue-router@^3.6.5: version "3.6.5" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.6.5.tgz#95847d52b9a7e3f1361cb605c8e6441f202afad8" integrity sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ==