Skip to content

Commit

Permalink
New Usereg (login 400)
Browse files Browse the repository at this point in the history
  • Loading branch information
84634E1A607A committed Jan 22, 2025
1 parent 3941669 commit 2f16d06
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 11 deletions.
7 changes: 7 additions & 0 deletions apps/thu-info-app/src/components/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ import {SchoolCalendar} from "../ui/home/schoolCalendar";
import {CampusCardScreen} from "../ui/home/campusCard";
import {TwoFactorAuthScreen} from "../ui/settings/twoFactorAuth.tsx";
import { IncomeScreen } from "../ui/home/income.tsx";
import { NetworkLoginScreen } from "../ui/home/networkLogin.tsx";

type RootTabParamList = {
HomeTab: undefined;
Expand Down Expand Up @@ -261,6 +262,7 @@ type HomeStackParamList = {
ECard: undefined;
ScheduleDetail: ScheduleDetailProps;
Network: undefined;
NetworkLogin: undefined;
NetworkDetail: undefined;
OnlineDevices: undefined;
SchoolCalendar: undefined;
Expand Down Expand Up @@ -762,6 +764,11 @@ export const Root = () => {
component={NetworkScreen}
options={{title: getStr("network")}}
/>
<Stack.Screen
name="NetworkLogin"
component={NetworkLoginScreen}
options={{title: getStr("networkLogin")}}
/>
<Stack.Screen
name="NetworkDetail"
component={NetworkDetailScreen}
Expand Down
13 changes: 11 additions & 2 deletions apps/thu-info-app/src/ui/home/network.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useColorScheme, View} from "react-native";
import { useColorScheme, View } from "react-native";
import {RootNav} from "../../components/Root";
import {currState} from "../../redux/store";
import { currState } from "../../redux/store";
import {SecondaryItem, styles} from "../../components/home/secondaryItems";
import {addUsageStat, FunctionType} from "../../utils/webApi";
import IconNetworkDetail from "../../assets/icons/IconNetworkDetail";
Expand All @@ -10,9 +10,18 @@ export const NetworkScreen = ({navigation}: {navigation: RootNav}) => {
const themeName = useColorScheme();
const style = styles(themeName);
const disabledFunction = currState().config.homeFunctionDisabled;

return (
<View style={style.SecondaryRootView}>
<View style={style.SecondaryContentView}>
<SecondaryItem
title="networkLogin"
destKey="networkLogin"
icon={<IconNetworkDetail />}
onPress={() => {
navigation.navigate("NetworkLogin");
}}
/>
{!disabledFunction.includes("networkDetail") && (
<SecondaryItem
title="networkDetail"
Expand Down
126 changes: 126 additions & 0 deletions apps/thu-info-app/src/ui/home/networkLogin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { RootNav } from "../../components/Root.tsx";
import { Image, Text, TouchableOpacity, useColorScheme, View } from "react-native";
import { styles } from "../../components/home/secondaryItems";
import * as Theme from "../../assets/themes/themes.ts";
import { helper } from "../../redux/store.ts";
import { useEffect, useState } from "react";
import { RoundedView } from "../../components/views.tsx";
import { CodeField, Cursor, useClearByFocusCell } from "react-native-confirmation-code-field";
import { getStr } from "../../utils/i18n.ts";
import Snackbar from "react-native-snackbar";

export const NetworkLoginScreen = ({ navigation }: { navigation: RootNav }) => {
const themeName = useColorScheme();
const style = styles(themeName);
const colors = Theme.default(themeName).colors;
const [verificationCode, setVerificationCode] = useState("");
const [imageUrl, setImageUrl] = useState<string | undefined>(undefined);

useEffect(() => {
helper.getNetworkVerificationImageUrl().then((url) => {
setImageUrl(url);
});
}, []);

const [props, getCellOnLayoutHandler] = useClearByFocusCell({

Check failure on line 25 in apps/thu-info-app/src/ui/home/networkLogin.tsx

View workflow job for this annotation

GitHub Actions / install-and-test

'props' is assigned a value but never used. Allowed unused elements of array destructuring patterns must match /^_/u
value: verificationCode,
setValue: setVerificationCode,
});

return (
<View style={style.SecondaryRootView}>
<RoundedView
style={{
borderRadius: 20,
alignItems: "center",
justifyContent: "center",
padding: 32,
paddingVertical: 32,
backgroundColor: colors.contentBackground,
display: "flex",
flexDirection: "column",
gap: 32,
}}>
<Text style={{
fontSize: 24,
color: colors.text,
}}>
{getStr("networkVerificationCode")}
</Text>
<View style={{
display: "flex", gap: 8,
alignItems: "center",
justifyContent: "center",
}}>
<TouchableOpacity
onPress={() => {
helper.getNetworkVerificationImageUrl().then((url) => {
setImageUrl(url);
});
}}>
<Image
source={{ uri: imageUrl }}
width={180}
height={68}
/>
</TouchableOpacity>
<Text style={{
fontSize: 16,
color: colors.fontB3

Check warning on line 69 in apps/thu-info-app/src/ui/home/networkLogin.tsx

View workflow job for this annotation

GitHub Actions / install-and-test

Missing trailing comma
}}>
{getStr("networkVerificationCodeRefreshHint")}
</Text>
</View>
<CodeField
value={verificationCode}
onChangeText={(v) => {
if (v.match(/^\d{0,4}$/)) {
setVerificationCode(v);
if (v.length === 4) {
helper.loginNetworkWithCode(v).then(() => {
navigation.pop();
}).catch((e) => {
setVerificationCode("");
Snackbar.show({
text: e.message,
duration: Snackbar.LENGTH_SHORT,
});
});
}
}
}}
cellCount={4}
autoFocus={false}
keyboardType="number-pad"
textContentType="oneTimeCode"
secureTextEntry={false}
renderCell={({ index, symbol, isFocused }) => (
<View
key={index}
style={{
width: "12.5%",
aspectRatio: 0.67,
paddingHorizontal: "auto",
paddingVertical: "auto",
borderWidth: 2,
borderColor: isFocused ? colors.mainTheme : colors.themeGrey,
borderRadius: 12,
justifyContent: "center",
marginLeft: index === 0 ? 0 : 12,
}}>
<Text
style={{
fontSize: 32,
textAlign: "center",
color: colors.primaryLight,
}}
onLayout={getCellOnLayoutHandler(index)}>
{symbol ? symbol : isFocused ? <Cursor /> : null}
</Text>
</View>
)}
/>
</RoundedView>
</View>
);
};
6 changes: 6 additions & 0 deletions apps/thu-info-app/src/utils/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ const translations = getLocale() as typeof zh;
export const langCode = translations === zh ? "zh" : "en";

export function getStr<K extends keyof typeof zh>(key: K): string {
// @ts-ignore
if (!translations[key]) {
console.warn(`Missing translation for key: ${key}, language: ${langCode}`);
return key;
}

// @ts-ignore
return translations[key];
}
1 change: 1 addition & 0 deletions packages/thu-info-lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"he": "^1.2.0",
"iconv-lite": "0.6.3",
"image-size": "^1.0.1",
"jsencrypt": "^3.3.2",
"jspdf": "^2.5.1",
"sm-crypto": "^0.3.13"
},
Expand Down
6 changes: 6 additions & 0 deletions packages/thu-info-lib/src/constants/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,12 @@ export const APP_SOCKET_STATUS_URL =
"https://app.cs.tsinghua.edu.cn/api/socket";
export const APP_PRIVACY_URL =
"https://app.cs.tsinghua.edu.cn/privacy";
export const NETWORK_VERIFICATION_CODE_URL =
"https://webvpn.tsinghua.edu.cn/https/77726476706e69737468656265737421e5e4448e223726446d0187ab9040227b54b6c80fcd73/site/captcha";
export const NETWORK_BASE_URL =
"https://webvpn.tsinghua.edu.cn/https/77726476706e69737468656265737421e5e4448e223726446d0187ab9040227b54b6c80fcd73/";
export const NETWORK_LOGIN_URL =
"https://webvpn.tsinghua.edu.cn/https/77726476706e69737468656265737421e5e4448e223726446d0187ab9040227b54b6c80fcd73/site/validate-user";
export const NETWORK_DETAIL_URL =
"https://webvpn.tsinghua.edu.cn/https/77726476706e69737468656265737421e5e4448e223726446d0187ab9040227b54b6c80fcd73/user_detail_statistics.php?action=query";
export const NETWORK_IMPORT_USER =
Expand Down
15 changes: 14 additions & 1 deletion packages/thu-info-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,14 @@ import {
submitFeedback,
} from "./lib/app";
import {MOCK_LATEST_VERSION} from "./mocks/app";
import { getNetworkBalance, getNetworkDetail, getOnlineDevices, loginNetwork, logoutNetwork } from "./lib/network";
import {
getNetworkBalance,
getNetworkDetail,
getNetworkVerificationCode,
getOnlineDevices, isNetworkLoggedIn,
loginNetwork,
logoutNetwork, loginNetworkWithCode
} from "./lib/network";
import {getScoreByCourseId} from "./lib/thos";
import {
canRechargeCampusCard,
Expand Down Expand Up @@ -966,6 +973,12 @@ export class InfoHelper {

public getFullDegreeProgram = async (degreeId?: number, skippedSet?: string[]) => getFullDegreeProgram(this, degreeId, skippedSet);

public getNetworkVerificationImageUrl = async () => getNetworkVerificationCode(this);

public loginNetworkWithCode = async (code: string) => loginNetworkWithCode(this, code);

public isNetworkLoggedIn = async () => isNetworkLoggedIn();

public getNetworkDetail = async (year: number, month: number) => getNetworkDetail(this, year, month);

public getOnlineDevices = async () => getOnlineDevices(this);
Expand Down
7 changes: 6 additions & 1 deletion packages/thu-info-lib/src/lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {IdAuthError, LibError, LoginError, UrlError} from "../utils/error";
import {loginCr} from "./cr";
import {sm2} from "sm-crypto";
import type {RTNNetworkUtils} from "rtn-network-utils";
import { loginUsereg } from "./network";

let getRedirectLocation: ((url: string) => Promise<string | null | undefined>) | undefined = undefined;
try {
Expand All @@ -38,7 +39,7 @@ try {
}
} catch { /* empty */ }

type RoamingPolicy = "default" | "id" | "id_website" | "card" | "cab" | "gitlab" | "cr";
type RoamingPolicy = "default" | "id" | "id_website" | "card" | "cab" | "gitlab" | "cr" | "net";

const HOST_MAP: { [key: string]: string } = {
"zhjw.cic": "77726476706e69737468656265737421eaff4b8b69336153301c9aa596522b20bc86e6e559a9b290",
Expand Down Expand Up @@ -321,6 +322,10 @@ export const roam = async (helper: InfoHelper, policy: RoamingPolicy, payload: s
await loginCr(helper);
return "";
}
case "net": {
await loginUsereg(helper, payload);
return "";
}
}
};

Expand Down
60 changes: 53 additions & 7 deletions packages/thu-info-lib/src/lib/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,66 @@ import {
NETWORK_IMPORT_IP, NETWORK_IMPORT_LOGIN,
NETWORK_IMPORT_USER,
NETWORK_USER_INFO,
NETWORK_1X_USER,
NETWORK_1X_USER, NETWORK_VERIFICATION_CODE_URL, NETWORK_LOGIN_URL, NETWORK_BASE_URL
} from "../constants/strings";
import { Device } from "../models/network/device";
import { Balance } from "../models/network/balance";
import { xEncode, xBase64Encode } from "../utils/srunCrypto";
import CryptoJS from "crypto-js/core";
import { JSEncrypt } from "jsencrypt";

export const webVPNTitle = "<title>清华大学WebVPN</title>";

let verification_code = "";
let emailName = "";

// Refresh and get verification code
export const getNetworkVerificationCode = async (helper: InfoHelper): Promise<string> => {
if (helper.mocked()) {
return "";
}

await uFetch(NETWORK_VERIFICATION_CODE_URL + "?refresh=1");
return NETWORK_VERIFICATION_CODE_URL + "?_=" + new Date().getTime();
};


export const loginNetworkWithCode = async (helper: InfoHelper, code: string): Promise<void> => {
verification_code = code;
await loginUsereg(helper, code);
};


export const isNetworkLoggedIn = async (): Promise<boolean> => {
const resp = await uFetch(NETWORK_BASE_URL);
return emailName != "" && resp.includes(emailName);
};


export const loginUsereg = async (helper: InfoHelper, code: string = verification_code): Promise<void> => {
const rsa_pubkey_str = cheerio.load(await uFetch(NETWORK_BASE_URL))("#public").val() as string;
const rsa_pubkey = new JSEncrypt();
rsa_pubkey.setPublicKey(rsa_pubkey_str);

emailName = (await helper.getUserInfo()).emailName;

const result = JSON.parse(await uFetch(NETWORK_LOGIN_URL, {
"LoginForm[username]": emailName,
"LoginForm[password]": rsa_pubkey.encrypt(helper.password),
"LoginForm[verifyCode]": code,
}));

if (result.success !== true) {
throw new LibError(result.message);
}
};


export const getNetworkDetail = async (helper: InfoHelper, year: number, month: number): Promise<Detial> =>
roamingWrapperWithMocks(
helper,
"default",
"66D157166A3E5EEB3C558B66803B2929",
"net",
verification_code,
async () => {
const resp = await uFetch(NETWORK_DETAIL_URL + `&year=${year}&month=${month}`);
if (resp === "请登录先" || resp.includes(webVPNTitle))
Expand Down Expand Up @@ -76,8 +122,8 @@ export const getNetworkDetail = async (helper: InfoHelper, year: number, month:

export const getOnlineDevices = async (helper: InfoHelper): Promise<Device[]> => roamingWrapperWithMocks(
helper,
"default",
"66D157166A3E5EEB3C558B66803B2929",
"net",
verification_code,
async () => {
const ret: Device[] = [];
const resp1 = await uFetch(NETWORK_IMPORT_USER);
Expand Down Expand Up @@ -149,8 +195,8 @@ export const getOnlineDevices = async (helper: InfoHelper): Promise<Device[]> =>
export const getNetworkBalance = async (helper: InfoHelper): Promise<Balance> =>
roamingWrapperWithMocks(
helper,
"default",
"66D157166A3E5EEB3C558B66803B2929",
"net",
verification_code,
async () => {
const resp = await uFetch(NETWORK_USER_INFO);
if (resp === "请登录先" || resp.includes(webVPNTitle))
Expand Down
3 changes: 3 additions & 0 deletions packages/thu-info-lib/src/utils/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ export const uFetch = async (
body: serialized ? (post as never as string) : stringify(post, paramEncoding),
};

console.log(url, init);

// Perform the network request
try {
// @ts-ignore
Expand All @@ -116,6 +118,7 @@ export const uFetch = async (
} catch {
throw new ResponseStatusError(`Unexpected response status code: ${response.status}`);
}
console.log(response.text());
throw new ResponseStatusError(`Unexpected response status code: ${response.status} (${path})`);
}

Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7263,6 +7263,11 @@ jscodeshift@^0.14.0:
temp "^0.8.4"
write-file-atomic "^2.3.0"

jsencrypt@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/jsencrypt/-/jsencrypt-3.3.2.tgz#b0f1a2278810c7ba1cb8957af11195354622df7c"
integrity sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==

jsesc@^3.0.2, jsesc@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e"
Expand Down

0 comments on commit 2f16d06

Please sign in to comment.