update
parent
65ac000169
commit
78b2b4b753
File diff suppressed because it is too large
Load Diff
|
@ -3,6 +3,10 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.7.1",
|
||||||
|
"@emotion/styled": "^11.6.0",
|
||||||
|
"@mui/icons-material": "^5.4.2",
|
||||||
|
"@mui/material": "^5.4.2",
|
||||||
"@testing-library/jest-dom": "^5.16.2",
|
"@testing-library/jest-dom": "^5.16.2",
|
||||||
"@testing-library/react": "^12.1.2",
|
"@testing-library/react": "^12.1.2",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
@ -40,6 +44,5 @@
|
||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
"devDependencies": {}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,5 +39,13 @@
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
-->
|
-->
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://fonts.googleapis.com/icon?family=Material+Icons"
|
||||||
|
/>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
38
src/App.css
38
src/App.css
|
@ -1,38 +0,0 @@
|
||||||
.App {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-logo {
|
|
||||||
height: 40vmin;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
.App-logo {
|
|
||||||
animation: App-logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-header {
|
|
||||||
background-color: #282c34;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: calc(10px + 2vmin);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-link {
|
|
||||||
color: #61dafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes App-logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { render, screen } from '@testing-library/react';
|
|
||||||
import App from './App';
|
|
||||||
|
|
||||||
test('renders learn react link', () => {
|
|
||||||
render(<App />);
|
|
||||||
const linkElement = screen.getByText(/learn react/i);
|
|
||||||
expect(linkElement).toBeInTheDocument();
|
|
||||||
});
|
|
191
src/App.tsx
191
src/App.tsx
|
@ -1,70 +1,167 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import Client from "mtproton/envs/browser";
|
import {
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Input,
|
||||||
|
InputAdornment,
|
||||||
|
Paper,
|
||||||
|
TextField,
|
||||||
|
} from "@mui/material";
|
||||||
|
import CountriesInput, { Country } from "./component/countriesInput";
|
||||||
|
import Telegram, { uploadBigFile } from "./telegram";
|
||||||
|
import SendIcon from "@mui/icons-material/Send";
|
||||||
|
import { User } from "./user";
|
||||||
|
import { Upload } from "@mui/icons-material";
|
||||||
|
import ab2str from "./utils/arraybuffer2str";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
let [countriesList, setcountriesList] = useState([] as any[]);
|
let [phone, setPhone] = useState("");
|
||||||
let phone = React.createRef<HTMLInputElement>();
|
let [code, setCode] = useState("");
|
||||||
|
let [phoneCodeHash, setPhoneCodeHash] = useState("");
|
||||||
useEffect(() => {
|
let [country, setCountry] = useState({} as Country | null);
|
||||||
let client = new Client({
|
let [user, setUser] = useState({} as User);
|
||||||
api_id: 18987971,
|
const [fileList, setFileList] = useState([]);
|
||||||
api_hash: "fcfd9e6ed3f9e48a360bb57cc0d59d98",
|
|
||||||
});
|
|
||||||
|
|
||||||
client.call("help.getCountriesList").then((result: any) => {
|
|
||||||
console.log("country:", result);
|
|
||||||
let resp: any[] = [];
|
|
||||||
result.countries.map((country: any) => {
|
|
||||||
// @ts-ignore
|
|
||||||
resp.push(
|
|
||||||
country.default_name + ": " + country.country_codes[0].country_code
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
setcountriesList(resp);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
let sendCode = () => {
|
let sendCode = () => {
|
||||||
console.log("phone:", phone.current?.value);
|
console.log("phone:", phone);
|
||||||
let client = new Client({
|
Telegram.call("auth.sendCode", {
|
||||||
api_id: 18987971,
|
phone_number: (country ? country.country_code : "") + phone,
|
||||||
api_hash: "fcfd9e6ed3f9e48a360bb57cc0d59d98",
|
|
||||||
});
|
|
||||||
client.setDefaultDc(5);
|
|
||||||
client
|
|
||||||
.call("auth.sendCode", {
|
|
||||||
phone_number: phone.current?.value,
|
|
||||||
settings: {
|
settings: {
|
||||||
_: "codeSettings",
|
_: "codeSettings",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((result: any) => {
|
.then((result: any) => {
|
||||||
console.log("auth.sendCode:", result);
|
console.log("auth.sendCode:", result);
|
||||||
|
setPhoneCodeHash(result.phone_code_hash);
|
||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error: any) => {
|
||||||
console.log("auth.sendCode:", error);
|
console.log("auth.sendCode:", error);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let login = () => {};
|
let login = () => {
|
||||||
|
console.log("auth code:", code);
|
||||||
|
console.log("auth hash code:", phoneCodeHash);
|
||||||
|
Telegram.call("auth.signIn", {
|
||||||
|
phone_number: (country ? country.country_code : "") + phone,
|
||||||
|
phone_code_hash: phoneCodeHash,
|
||||||
|
phone_code: code,
|
||||||
|
})
|
||||||
|
.then((result: any) => {
|
||||||
|
console.log("auth.signIn:", result);
|
||||||
|
setUser(result.user);
|
||||||
|
SendMessage();
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.log("auth.signIn:", error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let SendMessage = () => {
|
||||||
|
Telegram.call("messages.sendMessage", {
|
||||||
|
peer: {
|
||||||
|
_: "inputPeerSelf",
|
||||||
|
user_id: user.id,
|
||||||
|
},
|
||||||
|
message: "ice",
|
||||||
|
random_id: (10000 + Math.random() * (100000 - 10000))
|
||||||
|
.toFixed()
|
||||||
|
.toString(),
|
||||||
|
})
|
||||||
|
.then((result: any) => {
|
||||||
|
console.log("messages.sendMessage:", result);
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.log("messages.sendMessage:", error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let uploadFile = () => {
|
||||||
|
console.log("uploadFile:", fileList);
|
||||||
|
// @ts-ignore
|
||||||
|
uploadBigFile(fileList[0]?.bytes)
|
||||||
|
.then((file_id) => console.log("uploadFile ret:", file_id))
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("uploadFile error:", error);
|
||||||
|
alert(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let changeFile = (e: any) => {
|
||||||
|
console.log(e.target.files);
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function (event) {
|
||||||
|
if (event.target && event.target.result) {
|
||||||
|
let bytes = ab2str(event.target.result as ArrayBuffer);
|
||||||
|
console.log(bytes);
|
||||||
|
e.target.files[0].bytes = bytes;
|
||||||
|
setFileList(e.target.files);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsArrayBuffer(e.target.files[0]);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<Container maxWidth="sm">
|
||||||
<input ref={phone} />
|
<Paper
|
||||||
<button onClick={sendCode}>登录</button>
|
elevation={3}
|
||||||
<input />
|
sx={{
|
||||||
<button onClick={login}>登录</button>
|
padding: "150px 50px",
|
||||||
{countriesList.map((country: any, index) => {
|
position: "absolute",
|
||||||
return (
|
display: "flex",
|
||||||
<div key={index}>
|
flexDirection: "column",
|
||||||
{country}
|
justifyContent: "space-around",
|
||||||
<br />
|
height: "40%",
|
||||||
</div>
|
}}
|
||||||
);
|
>
|
||||||
})}
|
<CountriesInput
|
||||||
</div>
|
onChange={(country) => {
|
||||||
|
console.log(country);
|
||||||
|
setCountry(country);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label={"Phone Number"}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
{country && country.country_code
|
||||||
|
? "+" + country.country_code
|
||||||
|
: ""}
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
value={phone}
|
||||||
|
onChange={(e) => {
|
||||||
|
console.log(e.target.value);
|
||||||
|
setPhone(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label={"Auth Code"}
|
||||||
|
value={code}
|
||||||
|
onChange={(e) => {
|
||||||
|
console.log(e.target.value);
|
||||||
|
setCode(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{phoneCodeHash === "" ? (
|
||||||
|
<Button variant={"contained"} onClick={sendCode}>
|
||||||
|
发送验证码
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button variant={"contained"} onClick={login} endIcon={<SendIcon />}>
|
||||||
|
登录
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Input type="file" onChange={changeFile} />
|
||||||
|
<Button variant={"contained"} onClick={uploadFile} endIcon={<Upload />}>
|
||||||
|
上传
|
||||||
|
</Button>
|
||||||
|
</Paper>
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { Autocomplete, Box, TextField } from "@mui/material";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Telegram from "../telegram";
|
||||||
|
|
||||||
|
export interface Country {
|
||||||
|
default_name: string;
|
||||||
|
country_code: string;
|
||||||
|
// patterns?: string;
|
||||||
|
iso2: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CountriesInput(props: {
|
||||||
|
onChange: (country: Country | null) => void;
|
||||||
|
}) {
|
||||||
|
let [countriesList, setCountriesList] = useState([] as Country[]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Telegram.call("help.getCountriesList").then((result: any) => {
|
||||||
|
console.log("country:", result);
|
||||||
|
let resp: Country[] = [];
|
||||||
|
result.countries.map((country: any) => {
|
||||||
|
resp.push({
|
||||||
|
default_name: country.default_name,
|
||||||
|
country_code: country.country_codes[0].country_code,
|
||||||
|
// patterns:
|
||||||
|
// country.country_codes[0]?.patterns.length > 0
|
||||||
|
// ? country.country_codes[0]?.patterns[0]
|
||||||
|
// : "",
|
||||||
|
iso2: country.iso2,
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
setCountriesList(resp);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Autocomplete
|
||||||
|
disablePortal
|
||||||
|
autoHighlight
|
||||||
|
id="country-select"
|
||||||
|
options={countriesList.sort(function (a, b) {
|
||||||
|
const nameA = a.default_name.toUpperCase(); // ignore upper and lowercase
|
||||||
|
const nameB = b.default_name.toUpperCase(); // ignore upper and lowercase
|
||||||
|
if (nameA < nameB) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (nameA > nameB) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// names must be equal
|
||||||
|
return 0;
|
||||||
|
})}
|
||||||
|
sx={{ width: 300 }}
|
||||||
|
onChange={(_event, value) => {
|
||||||
|
props.onChange(value);
|
||||||
|
}}
|
||||||
|
getOptionLabel={(option) => option.default_name}
|
||||||
|
renderOption={(props, option) => (
|
||||||
|
<Box
|
||||||
|
component="li"
|
||||||
|
sx={{ "& > img": { mr: 2, flexShrink: 0 } }}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
loading="lazy"
|
||||||
|
width="20"
|
||||||
|
src={`https://flagcdn.com/w20/${option.iso2.toLowerCase()}.png`}
|
||||||
|
srcSet={`https://flagcdn.com/w40/${option.iso2.toLowerCase()}.png 2x`}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
{option.default_name} ({option.iso2}) +{option.country_code}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
renderInput={(params) => <TextField {...params} label="Country" />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CountriesInput;
|
|
@ -1,13 +0,0 @@
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
||||||
sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
||||||
monospace;
|
|
||||||
}
|
|
|
@ -1,14 +1,13 @@
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from "react-dom";
|
||||||
import './index.css';
|
import App from "./App";
|
||||||
import App from './App';
|
import reportWebVitals from "./reportWebVitals";
|
||||||
import reportWebVitals from './reportWebVitals';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<App />
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById("root")
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
// If you want to start measuring performance in your app, pass a function
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
import Client from "mtproton/envs/browser";
|
||||||
|
import between from "./utils/rand";
|
||||||
|
import exp from "constants";
|
||||||
|
|
||||||
|
class TelegramHelper {
|
||||||
|
private client: any;
|
||||||
|
constructor(appID: number, appHash: string) {
|
||||||
|
this.client = new Client({
|
||||||
|
api_id: appID,
|
||||||
|
api_hash: appHash,
|
||||||
|
test: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
async call(method: string, params?: object, options?: object) {
|
||||||
|
try {
|
||||||
|
return await this.client.call(method, params, options);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`${method} error:`, error);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const { error_code, error_message } = error;
|
||||||
|
|
||||||
|
// if (error_code === 420) {
|
||||||
|
// const seconds = Number(error_message.split('FLOOD_WAIT_')[1]);
|
||||||
|
// const ms = seconds * 1000;
|
||||||
|
//
|
||||||
|
// await sleep(ms);
|
||||||
|
//
|
||||||
|
// return this.call(method, params, options);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (error_code === 303) {
|
||||||
|
const [type, dcIdAsString] = error_message.split("_MIGRATE_");
|
||||||
|
|
||||||
|
const dcId = Number(dcIdAsString);
|
||||||
|
|
||||||
|
if (type === "PHONE") {
|
||||||
|
await this.client.setDefaultDc(dcId);
|
||||||
|
} else {
|
||||||
|
Object.assign(options, { dcId });
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.call(method, params, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uploadBigFile(bytes: string): Promise<number> {
|
||||||
|
let file_id = between(10000, 99999);
|
||||||
|
console.log("file_id", file_id);
|
||||||
|
|
||||||
|
const file_total_parts = Math.ceil(bytes.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 finished = await Telegram.call("upload.saveBigFilePart", {
|
||||||
|
file_id: file_id,
|
||||||
|
file_part: i,
|
||||||
|
file_total_parts: file_total_parts,
|
||||||
|
bytes: bytes.slice(i * 524288, (i + 1) * 524288),
|
||||||
|
});
|
||||||
|
if (finished) {
|
||||||
|
console.log("finished");
|
||||||
|
} else {
|
||||||
|
console.log("not finished");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("uploaded");
|
||||||
|
return file_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const appID = 18987971;
|
||||||
|
const appHash = "fcfd9e6ed3f9e48a360bb57cc0d59d98";
|
||||||
|
let Telegram = new TelegramHelper(appID, appHash);
|
||||||
|
|
||||||
|
export default Telegram;
|
||||||
|
export { uploadBigFile };
|
|
@ -0,0 +1,29 @@
|
||||||
|
export interface Status {
|
||||||
|
_: string;
|
||||||
|
was_online: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface User {
|
||||||
|
_: string;
|
||||||
|
flags: number;
|
||||||
|
self: boolean;
|
||||||
|
contact: boolean;
|
||||||
|
mutual_contact: boolean;
|
||||||
|
deleted: boolean;
|
||||||
|
bot: boolean;
|
||||||
|
bot_chat_history: boolean;
|
||||||
|
bot_nochats: boolean;
|
||||||
|
verified: boolean;
|
||||||
|
restricted: boolean;
|
||||||
|
min: boolean;
|
||||||
|
bot_inline_geo: boolean;
|
||||||
|
support: boolean;
|
||||||
|
scam: boolean;
|
||||||
|
apply_min_photo: boolean;
|
||||||
|
fake: boolean;
|
||||||
|
id: string;
|
||||||
|
access_hash: string;
|
||||||
|
first_name: string;
|
||||||
|
phone: string;
|
||||||
|
status: Status;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
function ArraybufferToStr(buffer: ArrayBuffer) {
|
||||||
|
let uint8 = new Uint8Array(buffer);
|
||||||
|
|
||||||
|
let decoder = new TextDecoder("utf8");
|
||||||
|
return decoder.decode(uint8);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ArraybufferToStr;
|
|
@ -0,0 +1,5 @@
|
||||||
|
function between(min: number, max: number): number {
|
||||||
|
return Math.floor(Math.random() * (max - min) + min);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default between;
|
Loading…
Reference in New Issue