diff --git a/package.json b/package.json index 449f230..486be9c 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,16 @@ "private": true, "main": "main.js", "dependencies": { + "@headlessui/react": "^0.0.0-insiders.ab6310c", + "@rsuite/icons": "^1.0.2", + "electron": "^18.0.2", + "electron-store": "^8.0.1", + "mtproton": "^6.0.0", "react": "^18.0.0", "react-dom": "^18.0.0", - "react-scripts": "5.0.0" + "react-router-dom": "^6.3.0", + "react-scripts": "5.0.0", + "rsuite": "^5.8.0" }, "scripts": { "start": "react-scripts start", @@ -17,7 +24,6 @@ }, "devDependencies": { "autoprefixer": "^10.4.4", - "electron": "^18.0.1", "postcss": "^8.4.12", "tailwindcss": "^3.0.23" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b7cca3a..e380a8f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,6 +6,7 @@ specifiers: autoprefixer: ^10.4.4 electron: ^18.0.2 electron-store: ^8.0.1 + mtproton: ^6.0.0 postcss: ^8.4.12 react: ^18.0.0 react-dom: ^18.0.0 @@ -19,6 +20,7 @@ dependencies: '@rsuite/icons': registry.npmmirror.com/@rsuite/icons/1.0.2_react-dom@18.0.0+react@18.0.0 electron: registry.npmmirror.com/electron/18.0.2 electron-store: registry.npmmirror.com/electron-store/8.0.1 + mtproton: registry.npmmirror.com/mtproton/6.0.0 react: registry.npmmirror.com/react/18.0.0 react-dom: registry.npmmirror.com/react-dom/18.0.0_react@18.0.0 react-router-dom: registry.npmmirror.com/react-router-dom/6.3.0_react-dom@18.0.0+react@18.0.0 @@ -3283,6 +3285,12 @@ packages: regex-parser: registry.npmmirror.com/regex-parser/2.2.11 dev: false + registry.npmmirror.com/aes-js/3.1.2: + resolution: {integrity: sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/aes-js/-/aes-js-3.1.2.tgz} + name: aes-js + version: 3.1.2 + dev: false + registry.npmmirror.com/agent-base/6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz} name: agent-base @@ -3817,6 +3825,13 @@ packages: tryer: registry.npmmirror.com/tryer/1.0.1 dev: false + registry.npmmirror.com/big-integer/1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/big-integer/-/big-integer-1.6.51.tgz} + name: big-integer + version: 1.6.51 + engines: {node: '>=0.6'} + dev: false + registry.npmmirror.com/big.js/5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz} name: big.js @@ -4351,6 +4366,20 @@ packages: dev: false optional: true + registry.npmmirror.com/configstore/5.0.1: + resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/configstore/-/configstore-5.0.1.tgz} + name: configstore + version: 5.0.1 + engines: {node: '>=8'} + dependencies: + dot-prop: registry.npmmirror.com/dot-prop/5.3.0 + graceful-fs: registry.npmmirror.com/graceful-fs/4.2.9 + make-dir: registry.npmmirror.com/make-dir/3.1.0 + unique-string: registry.npmmirror.com/unique-string/2.0.0 + write-file-atomic: registry.npmmirror.com/write-file-atomic/3.0.3 + xdg-basedir: registry.npmmirror.com/xdg-basedir/4.0.0 + dev: false + registry.npmmirror.com/confusing-browser-globals/1.0.11: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz} name: confusing-browser-globals @@ -4806,6 +4835,20 @@ packages: ms: registry.npmmirror.com/ms/2.1.3 dev: false + registry.npmmirror.com/debug/4.3.3: + resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/debug/-/debug-4.3.3.tgz} + name: debug + version: 4.3.3 + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: registry.npmmirror.com/ms/2.1.2 + dev: false + registry.npmmirror.com/debug/4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz} name: debug @@ -5143,6 +5186,15 @@ packages: tslib: registry.npmmirror.com/tslib/2.3.1 dev: false + registry.npmmirror.com/dot-prop/5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dot-prop/-/dot-prop-5.3.0.tgz} + name: dot-prop + version: 5.3.0 + engines: {node: '>=8'} + dependencies: + is-obj: registry.npmmirror.com/is-obj/2.0.0 + dev: false + registry.npmmirror.com/dot-prop/6.0.1: resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dot-prop/-/dot-prop-6.0.1.tgz} name: dot-prop @@ -7973,6 +8025,12 @@ packages: language-subtag-registry: registry.npmmirror.com/language-subtag-registry/0.3.21 dev: false + registry.npmmirror.com/leemon/6.2.0: + resolution: {integrity: sha512-a5ieuGSGEb5ezCL6UNds5//cVFaKpeexVK0VDCE8/eOF0r0/9Og94LQ33U2Px5dUcHVCDPWQY8gXLgDlDJnyyg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/leemon/-/leemon-6.2.0.tgz} + name: leemon + version: 6.2.0 + dev: false + registry.npmmirror.com/leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/leven/-/leven-3.1.0.tgz} name: leven @@ -8359,6 +8417,24 @@ packages: version: 2.1.3 dev: false + registry.npmmirror.com/mtproton/6.0.0: + resolution: {integrity: sha512-tANtt9UXKuvDf/lJmDH2LLozHQw6aUnKk7JSMz695db5NnuoFg6h9r5u32Ajhdvuw+ZILIajJm3/T/mZt6QAIg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mtproton/-/mtproton-6.0.0.tgz} + name: mtproton + version: 6.0.0 + engines: {node: '>=12'} + dependencies: + aes-js: registry.npmmirror.com/aes-js/3.1.2 + big-integer: registry.npmmirror.com/big-integer/1.6.51 + configstore: registry.npmmirror.com/configstore/5.0.1 + debug: registry.npmmirror.com/debug/4.3.3 + events: registry.npmmirror.com/events/3.3.0 + leemon: registry.npmmirror.com/leemon/6.2.0 + lodash.debounce: registry.npmmirror.com/lodash.debounce/4.0.8 + pako: registry.npmmirror.com/pako/2.0.4 + transitivePeerDependencies: + - supports-color + dev: false + registry.npmmirror.com/multicast-dns-service-types/1.1.0: resolution: {integrity: sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz} name: multicast-dns-service-types @@ -8778,6 +8854,12 @@ packages: engines: {node: '>=6'} dev: false + registry.npmmirror.com/pako/2.0.4: + resolution: {integrity: sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/pako/-/pako-2.0.4.tgz} + name: pako + version: 2.0.4 + dev: false + registry.npmmirror.com/param-case/3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/param-case/-/param-case-3.0.4.tgz} name: param-case @@ -12512,6 +12594,13 @@ packages: optional: true dev: false + registry.npmmirror.com/xdg-basedir/4.0.0: + resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz} + name: xdg-basedir + version: 4.0.0 + engines: {node: '>=8'} + dev: false + registry.npmmirror.com/xml-name-validator/3.0.0: resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz} name: xml-name-validator diff --git a/src/Loading.js b/src/Loading.js new file mode 100644 index 0000000..a8cd0d9 --- /dev/null +++ b/src/Loading.js @@ -0,0 +1,27 @@ +import React, { useEffect } from "react"; +import SpinnerIcon from "@rsuite/icons/legacy/Spinner"; +import { getMe } from "./telegram/user"; + +function Loading() { + useEffect(() => { + setTimeout(() => { + window.location.href = "/guide"; + }, 3000); + getMe() + .then((res) => { + console.log(res); + // window.location.href = "/guide"; + }) + .catch((err) => { + console.log(err); + window.location.href = "/guide"; + }); + }, []); + return ( +
+ +
+ ); +} + +export default Loading; diff --git a/src/Login.js b/src/Login.js deleted file mode 100644 index 85cd9f5..0000000 --- a/src/Login.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useEffect } from "react"; -import { Badge, Button, Input, InputGroup } from "rsuite"; - -function Login() { - useEffect(() => { - window.windows.reSize(600, 600); - }); - return ( -
-
-
-
登录账号
-
- fileset.io -
-
-
- - - - - - - 忘记密码 - -
- 还没有fileset.io账号? -
-
-
-
- ); -} - -export default Login; diff --git a/src/index.js b/src/index.js index b869102..f214a30 100644 --- a/src/index.js +++ b/src/index.js @@ -10,13 +10,14 @@ import Safebox from "./content/Safebox"; import Recycle from "./content/Recycle"; import Share from "./content/Share"; import Transfer from "./content/Transfer"; -import SpinnerIcon from "@rsuite/icons/legacy/Spinner"; -import Login from "./Login"; +import Login from "./login/Login"; import "rsuite/dist/rsuite.min.css"; import { CustomProvider } from "rsuite"; import { zhCN } from "rsuite/locales"; -import Guide from "./Guide"; +import Guide from "./login/Guide"; +import Loading from "./Loading"; +import Register from "./login/Register"; ReactDOMClient.createRoot(document.getElementById("root")).render( @@ -24,6 +25,8 @@ ReactDOMClient.createRoot(document.getElementById("root")).render( }> }> + }> + }> }> } /> } /> @@ -33,21 +36,7 @@ ReactDOMClient.createRoot(document.getElementById("root")).render( } /> } /> - }> ); - -function Loading() { - useEffect(() => { - setTimeout(() => { - window.location.href = "/guide"; - }, 1000); - }, []); - return ( -
- -
- ); -} diff --git a/src/Guide.js b/src/login/Guide.js similarity index 100% rename from src/Guide.js rename to src/login/Guide.js diff --git a/src/login/Login.js b/src/login/Login.js new file mode 100644 index 0000000..80ddfeb --- /dev/null +++ b/src/login/Login.js @@ -0,0 +1,64 @@ +import React from "react"; +import { Button, Form, Schema } from "rsuite"; +import Header from "./header"; + +const loginModel = Schema.Model({ + email: Schema.Types.StringType().isEmail("请输入正确的格式"), + password: Schema.Types.StringType() + .rangeLength(6, 20, "密码长度为6-20位") + .isRequired("密码不能为空"), +}); + +function Login() { + const formRef = React.useRef(); + const [formValue, setFormValue] = React.useState({}); + + let login = () => { + console.log(formValue); + if (formRef.current.check()) { + console.log("验证通过"); + } + }; + + return ( +
+
+
+
+
+ + + + + + +
+ 忘记密码 + +
+ + 还没有fileset.io账号? + +
+
+
+
+ ); +} + +export default Login; diff --git a/src/login/Register.js b/src/login/Register.js new file mode 100644 index 0000000..32b7a8f --- /dev/null +++ b/src/login/Register.js @@ -0,0 +1,81 @@ +import { Button, Form, Input, InputGroup, Schema } from "rsuite"; +import React from "react"; +import Header from "./header"; + +const registerModel = Schema.Model({ + email: Schema.Types.StringType() + .isEmail("请输入正确的格式") + .isRequired("请输入邮箱"), + password: Schema.Types.StringType() + .rangeLength(6, 20, "密码长度为6-20位") + .isRequired("密码不能为空"), + confirm_password: Schema.Types.StringType() + .isRequired("确认密码不能为空") + .addRule(function (value, data) { + return value === data.password; + }, "两次密码不一致"), + nickname: Schema.Types.StringType() + .isRequired("昵称不能为空") + .rangeLength(2, 20, "昵称长度为2-20位"), +}); + +function Register() { + const formRef = React.useRef(); + const [formValue, setFormValue] = React.useState({}); + + let register = () => { + console.log(formValue); + if (formRef.current.check()) { + console.log("校验通过"); + } + }; + return ( +
+
+
+
+
+
+ + + + + + + + + + + + +
+ + +
+
+
+
+ ); +} + +export default Register; diff --git a/src/login/header.js b/src/login/header.js new file mode 100644 index 0000000..01aa23c --- /dev/null +++ b/src/login/header.js @@ -0,0 +1,17 @@ +import React, { useEffect } from "react"; + +function Header(props) { + useEffect(() => { + window.windows.reSize(600, 600); + }); + return ( + <> +
+
{props.title}
+
fileset.io
+
+ + ); +} + +export default Header; diff --git a/src/telegram/telegram.js b/src/telegram/telegram.js new file mode 100644 index 0000000..34c79be --- /dev/null +++ b/src/telegram/telegram.js @@ -0,0 +1,228 @@ +import Client from "mtproton/envs/browser"; +import makeMTProto from "mtproton/src/index"; +import SHA1 from "mtproton/envs/browser/sha1"; +import SHA256 from "mtproton/envs/browser/sha256"; +import PBKDF2 from "mtproton/envs/browser/pbkdf2"; +import Transport from "mtproton/envs/browser/transport"; +import getRandomBytes from "mtproton/envs/browser/get-random-bytes"; +import getLocalStorage from "mtproton/envs/browser/get-local-storage"; + +class TelegramHelper { + constructor(appID, appHash, custom = false) { + if (!custom) { + this.client = new Client({ + api_id: appID, + api_hash: appHash, + test: false, + }); + } else { + let createTransport = function (dc, crypto) { + return new Transport(dc, crypto); + }; + + const MTProto = makeMTProto({ + SHA1, + SHA256, + PBKDF2, + getRandomBytes, + getLocalStorage, + createTransport, + }); + + this.client = new MTProto({ + api_id: appID, + api_hash: appHash, + test: true, + }); + } + // this.client.setDefaultDc(2); + } + + async call(method, params, options, hideLog = false) { + try { + !hideLog && console.log(`${method} req\n${params}`); + options = { + ...options, + }; + let resp = await this.client.call(method, params, options); + !hideLog && console.dir(`${method} resp\n${resp}`); + return resp; + } catch (error) { + !hideLog && console.log(`${method} error:`, error); + + const { error_code, error_message } = error; + + if (error_code === 303) { + const [, dcIdAsString] = error_message.split("_MIGRATE_"); + + const dcId = Number(dcIdAsString); + + await this.client.setDefaultDc(dcId); + + return this.call(method, params, options); + } + return Promise.reject(error); + } + } +} + +async function uploadBigFile(bytes, callback) { + let file_id = rand_id(); + console.log("file_id", file_id); + + let uploadBytes = new Uint8Array(bytes); + console.log("uploading file", bytes); + const file_total_parts = Math.ceil(uploadBytes.length / 524288); + console.log("file_total_parts", file_total_parts); + for (let i = 0; i < file_total_parts; i++) { + console.log("push part: ", i); + try { + let tempBytes = uploadBytes.slice(i * 524288, (i + 1) * 524288); + if (i === file_total_parts - 1) { + tempBytes = uploadBytes.slice(i * 524288); + } + console.log("tempBytes", tempBytes); + let finished = await Telegram.call("upload.saveBigFilePart", { + file_id: file_id, + file_part: i, + file_total_parts: file_total_parts, + bytes: tempBytes, + }); + console.log("finished", finished); + if (callback) { + callback(((i + 1) / file_total_parts) * 100); + } + } catch (error) { + return Promise.reject(error); + } + } + + console.log("uploaded"); + return { file_id: file_id, total_part: file_total_parts }; +} + +function inputFile(file_id, part_number, file_name) { + return { + _: "inputFileBig", + id: file_id, + parts: part_number, + name: file_name, + }; +} + +function sendFile(inputFile, type) { + let random_id = rand_id(); + console.log("random_id", random_id); + return Telegram.call("messages.sendMedia", { + peer: { + _: "inputPeerSelf", + }, + media: { + _: "inputMediaUploadedDocument", + file: inputFile, + mime_type: type, + attributes: [ + { + _: "documentAttributeFilename", + file_name: inputFile.name, + }, + ], + }, + random_id: rand_id(), + message: "test", + }); +} + +async function downloadFile(fileDocument) { + let partSize = 1024 * 1024; + const file_total_parts = Math.ceil(fileDocument.size / partSize); + + let results = []; + for (let i = 0; i < file_total_parts; i++) { + try { + let result = await Telegram.call("upload.getFile", { + location: { + _: "inputDocumentFileLocation", + id: fileDocument.id, + access_hash: fileDocument.access_hash, + file_reference: fileDocument.file_reference, + thumb_size: "", + }, + limit: partSize, + offset: partSize * i, + }); + console.log("result", result); + results.push(result); + } catch (error) { + return Promise.reject(error); + } + } + + console.log("messages.getDocument:", results); + let bytes = new Uint8Array(fileDocument.size); + for (let i = 0; i < results.length; i++) { + for (let j = 0; j < results[i].bytes.length; j++) { + bytes[i * partSize + j] = results[i].bytes[j]; + } + } + let downloadBytes = bytes; + console.log("downloadBytes", downloadBytes); + let blob = new Blob([downloadBytes], { + type: fileDocument.mime_type, + }); + let url = window.URL.createObjectURL(blob); + let a = document.createElement("a"); + a.href = url; + a.download = fileDocument.file_name; + a.click(); + return Promise.resolve(true); +} + +async function sendSignInCode(phone) { + try { + let result = await Telegram.call("auth.sendCode", { + phone_number: phone, + settings: { + _: "codeSettings", + }, + }); + return Promise.resolve(result.phone_code_hash); + } catch (error) { + return Promise.reject(error); + } +} + +async function signIn(phone, code, phone_code_hash) { + try { + let result = await Telegram.call("auth.signIn", { + phone_number: phone, + phone_code_hash: phone_code_hash, + phone_code: code, + }); + return Promise.resolve(result); + } catch (error) { + return Promise.reject(error); + } +} + +function between(min, max) { + return Math.floor(Math.random() * (max - min) + min); +} + +function rand_id() { + return between(100000, 999999); +} + +const appID = 18987971; +const appHash = "fcfd9e6ed3f9e48a360bb57cc0d59d98"; +let Telegram = new TelegramHelper(appID, appHash); + +export default Telegram; +export { + uploadBigFile, + inputFile, + sendFile, + downloadFile, + sendSignInCode, + signIn, +}; diff --git a/src/telegram/user.js b/src/telegram/user.js new file mode 100644 index 0000000..084ab12 --- /dev/null +++ b/src/telegram/user.js @@ -0,0 +1,9 @@ +import Telegram from "./telegram"; + +async function getMe() { + return await Telegram.call("users.getFullUser", { + id: { _: "inputUserSelf" }, + }); +} + +export { getMe };