feat: convinient login

This commit is contained in:
TrèsAbhi committed 2024-05-01 13:04:31 -05:00
1 parent 6223773c71
commit 6e32b41b15
7 files changed
+186 -13

No files matched your search

+5 -6
View File
@@ -14,7 +14,7 @@ import { debounce } from 'lodash';
import { useEffect, useRef, useState } from 'react';
import PageWrapper from '../../../components/PageWrapper';
import { UNLOCALIZED_REGION_NAMES_SHORT } from '../../../constants/regions';
import { WARGAMING_APPLICATION_ID } from '../../../constants/wargamingApplicationID';
import { authURL } from '../../../core/blitz/authURL';
import { getAccountInfo } from '../../../core/blitz/getAccountInfo';
import getTankStats from '../../../core/blitz/getTankStats';
import { idToRegion } from '../../../core/blitz/idToRegion';
@@ -117,11 +117,10 @@ export default function Page() {
</AlertDialog.Cancel>
<AlertDialog.Action>
<Link
href={`https://api.worldoftanks.${
(session as SessionTracking).player.region
}/wot/auth/login/?application_id=${WARGAMING_APPLICATION_ID}&redirect_uri=${encodeURIComponent(
`${location.origin}/callback/wargaming/?return=${location.href}`,
)}`}
href={authURL(
(session as SessionTracking).player.region,
location.href,
)}
>
<Button variant="solid">Sign in</Button>
</Link>
@@ -0,0 +1,22 @@
import { ExitIcon } from '@radix-ui/react-icons';
import { Flex, IconButton, Text } from '@radix-ui/themes';
import { use } from 'react';
import { getAccountInfo } from '../../../core/blitz/getAccountInfo';
import { idToRegion } from '../../../core/blitz/idToRegion';
import { logout } from '../../../core/blitz/logout';
import { useApp } from '../../../stores/app';
export function LoggedIn() {
const login = useApp((state) => state.login!);
const accountInfo = use(getAccountInfo(idToRegion(login.id), login.id));
return (
<Flex gap="3" align="center">
<Text>Hello, {accountInfo.nickname}</Text>
<IconButton variant="ghost" color="red" onClick={logout}>
<ExitIcon />
</IconButton>
</Flex>
);
}
+76 -2
View File
@@ -2,25 +2,50 @@ import {
DiscordLogoIcon,
GearIcon,
HamburgerMenuIcon,
PersonIcon,
} from '@radix-ui/react-icons';
import {
Button,
Flex,
Heading,
IconButton,
Link as LinkRadix,
Popover,
Select,
Spinner,
Text,
} from '@radix-ui/themes';
import Link from 'next/link';
import { Suspense, useEffect, useState } from 'react';
import { Region } from '../../constants/regions';
import { TOOLS } from '../../constants/tools';
import { authURL } from '../../core/blitz/authURL';
import { extendAuth } from '../../core/blitz/extendAuth';
import { logout } from '../../core/blitz/logout';
import { useFullScreen } from '../../hooks/useFullScreen';
import { useWideFormat } from '../../hooks/useWideFormat';
import { BlitzkitWide } from '../../icons/BlitzkitWide';
import { PatreonIcon } from '../../icons/Patreon';
import { theme } from '../../stitches.config';
import { useApp } from '../../stores/app';
import { LoggedIn } from './components/LoggedIn';
export default function Navbar() {
const isFullScreen = useFullScreen();
const wideFormat = useWideFormat(600);
const login = useApp((state) => state.login);
const [region, setRegion] = useState<Region>('com');
useEffect(() => {
if (!login) return;
const expiresIn = login.expiresAt - Date.now() / 1000;
const expiresInDays = expiresIn / 60 / 60 / 24;
if (expiresInDays < 0) {
logout();
} else if (expiresInDays < 7) {
extendAuth();
}
});
if (isFullScreen) return null;
@@ -89,6 +114,7 @@ export default function Navbar() {
>
<PatreonIcon width={14} height={14} />
</Link>
<div style={{ width: 14, height: 14 }} />
<div style={{ flex: 1 }} />
@@ -153,6 +179,54 @@ export default function Navbar() {
</Flex>
</Popover.Content>
</Popover.Root>
<Popover.Root>
<Popover.Trigger>
<IconButton variant="ghost" color="gray">
<PersonIcon />
</IconButton>
</Popover.Trigger>
<Popover.Content align="center">
<Flex direction="column" gap="2">
{login && (
<Suspense fallback={<Spinner />}>
<LoggedIn />
</Suspense>
)}
{!login && (
<>
<Text color="gray">Currently signed out</Text>
<Flex gap="2">
<Select.Root
value={region}
onValueChange={(value) => setRegion(value as Region)}
>
<Select.Trigger />
<Select.Content>
<Select.Item value={'com' satisfies Region}>
North America
</Select.Item>
<Select.Item value={'eu' satisfies Region}>
Europe
</Select.Item>
<Select.Item value={'asia' satisfies Region}>
Asia
</Select.Item>
</Select.Content>
</Select.Root>
<LinkRadix href={authURL(region)}>
<Button>Sign in</Button>
</LinkRadix>
</Flex>
</>
)}
</Flex>
</Popover.Content>
</Popover.Root>
</Flex>
</Flex>
</div>
+8
View File
@@ -0,0 +1,8 @@
import { Region } from '../../constants/regions';
import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID';
export function authURL(region: Region, callback?: string) {
return `https://api.worldoftanks.${region}/wot/auth/login/?application_id=${WARGAMING_APPLICATION_ID}&redirect_uri=${encodeURIComponent(
`${location.origin}/callback/wargaming/${callback ? `?return=${location.href}` : ''}`,
)}`;
}
+59
View File
@@ -0,0 +1,59 @@
import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID';
import { mutateApp, useApp } from '../../stores/app';
import { idToRegion } from './idToRegion';
interface Extension {
data: {
access_token: string;
account_id: number;
expires_at: number;
};
}
export async function extendAuth() {
const { login } = useApp.getState();
if (!login) return;
// error handling? what's that?
/*
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠙⠛⠛⠛⠿⠻⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⡀⠠⠤⠒⢂⣉⣉⣉⣑⣒⣒⠒⠒⠒⠒⠒⠒⠒⠀⠀⠐⠒⠚⠻⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⡠⠔⠉⣀⠔⠒⠉⣀⣀⠀⠀⠀⣀⡀⠈⠉⠑⠒⠒⠒⠒⠒⠈⠉⠉⠉⠁⠂⠀⠈⠙⢿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠔⠁⠠⠖⠡⠔⠊⠀⠀⠀⠀⠀⠀⠀⠐⡄⠀⠀⠀⠀⠀⠀⡄⠀⠀⠀⠀⠉⠲⢄⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠊⠀⢀⣀⣤⣤⣤⣤⣀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠜⠀⠀⠀⠀⣀⡀⠀⠈⠃⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⡿⠥⠐⠂⠀⠀⠀⠀⡄⠀⠰⢺⣿⣿⣿⣿⣿⣟⠀⠈⠐⢤⠀⠀⠀⠀⠀⠀⢀⣠⣶⣾⣯⠀⠀⠉⠂⠀⠠⠤⢄⣀⠙⢿⣿⣿⣿⣿
⣿⡿⠋⠡⠐⠈⣉⠭⠤⠤⢄⡀⠈⠀⠈⠁⠉⠁⡠⠀⠀⠀⠉⠐⠠⠔⠀⠀⠀⠀⠀⠲⣿⠿⠛⠛⠓⠒⠂⠀⠀⠀⠀⠀⠀⠠⡉⢢⠙⣿⣿⣿
⣿⠀⢀⠁⠀⠊⠀⠀⠀⠀⠀⠈⠁⠒⠂⠀⠒⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⢀⣀⡠⠔⠒⠒⠂⠀⠈⠀⡇⣿⣿⣿⣿⣿
⣿⠀⢸⠀⠀⠀⢀⣀⡠⠋⠓⠤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠀⠀⠀⠀⠀⠈⠢⠤⡀⠀⠀⠀⠀⠀⠀⢠⠀⠀⠀⡠⠀⡇⣿⣿⣿⣿⣿
⣿⡀⠘⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠈⠑⡦⢄⣀⠀⠀⠐⠒⠁⢸⠀⠀⠠⠒⠄⠀⠀⠀⠀⠀⢀⠇⠀⣀⡀⠀⠀⢀⢾⡆⠀⠈⡀⠎⣸⣿⣿⣿
⣿⣿⣄⡈⠢⠀⠀⠀⠀⠘⣶⣄⡀⠀⠀⡇⠀⠀⠈⠉⠒⠢⡤⣀⡀⠀⠀⠀⠀⠀⠐⠦⠤⠒⠁⠀⠀⠀⠀⣀⢴⠁⠀⢷⠀⠀⠀⢰⣿⣿⣿⣿
⣿⣿⣿⣿⣇⠂⠀⠀⠀⠀⠈⢂⠀⠈⠹⡧⣀⠀⠀⠀⠀⠀⡇⠀⠀⠉⠉⠉⢱⠒⠒⠒⠒⢖⠒⠒⠂⠙⠏⠀⠘⡀⠀⢸⠀⠀⠀⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠑⠄⠰⠀⠀⠁⠐⠲⣤⣴⣄⡀⠀⠀⠀⠀⢸⠀⠀⠀⠀⢸⠀⠀⠀⠀⢠⠀⣠⣷⣶⣿⠀⠀⢰⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠁⢀⠀⠀⠀⠀⠀⡙⠋⠙⠓⠲⢤⣤⣷⣤⣤⣤⣤⣾⣦⣤⣤⣶⣿⣿⣿⣿⡟⢹⠀⠀⢸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠑⠀⢄⠀⡰⠁⠀⠀⠀⠀⠀⠈⠉⠁⠈⠉⠻⠋⠉⠛⢛⠉⠉⢹⠁⢀⢇⠎⠀⠀⢸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣀⠈⠢⢄⡉⠂⠄⡀⠀⠈⠒⠢⠄⠀⢀⣀⣀⣰⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⢀⣎⠀⠼⠊⠀⠀⠀⠘⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⡀⠉⠢⢄⡈⠑⠢⢄⡀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⢀⠀⠀⠀⠀⠀⢻⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣀⡈⠑⠢⢄⡀⠈⠑⠒⠤⠄⣀⣀⠀⠉⠉⠉⠉⠀⠀⠀⣀⡀⠤⠂⠁⠀⢀⠆⠀⠀⢸⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣄⡀⠁⠉⠒⠂⠤⠤⣀⣀⣉⡉⠉⠉⠉⠉⢀⣀⣀⡠⠤⠒⠈⠀⠀⠀⠀⣸⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣶⣶⣤⣤⣤⣤⣀⣀⣤⣤⣤⣶⣾⣿⣿⣿⣿⣿
*/
const response = await fetch(
`https://api.worldoftanks.${idToRegion(
login.id,
)}/wot/auth/prolongate/?application_id=${WARGAMING_APPLICATION_ID}&access_token=${
login.token
}`,
);
const json = (await response.json()) as Extension;
mutateApp((draft) => {
draft.login = {
id: login.id,
token: json.data.access_token,
expiresAt: json.data.expires_at,
};
});
}
+7
View File
@@ -0,0 +1,7 @@
import { mutateApp } from '../../stores/app';
export function logout() {
mutateApp((draft) => {
draft.login = undefined;
});
}
+9 -5
View File
@@ -1,5 +1,5 @@
import AdmZip from 'adm-zip';
import { readFile } from 'fs/promises';
import { readFile, writeFile } from 'fs/promises';
import { Parser } from 'pickleparser';
import protobuf from 'protobufjs';
import { ReadStream } from './buffer';
@@ -42,10 +42,14 @@ export class WotbReplayReadStream extends ReadStream {
'BattleResultsGenerated.BattleResultsClient',
);
const decodedBattleResults = BattleResults.decode(
Buffer.from(battleResultsString, 'binary'),
);
console.log(decodedBattleResults.toJSON());
writeFile('test.dat', Buffer.from(battleResultsString));
const reader = protobuf.Reader.create(Buffer.from(battleResultsString));
// const decodedBattleResults = BattleResults.decodeDelimited(
// Buffer.from(battleResultsString),
// );
// console.log(decodedBattleResults.toJSON());
}
}