SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
This commit is contained in:
commit
fa9c73363d
1367 files changed
+355735
No files matched your search
@@ -0,0 +1,176 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { protobuf_encode } from '@snowluma/proton';
|
||||
import type { OidbBase, OidbSvcTrpcTcp0xFD4_1Response } from '@snowluma/proto-defs/oidb';
|
||||
import type { OidbUserInfoResponse } from '@snowluma/proto-defs/oidb-actions/base';
|
||||
import { FetchFriendListPage } from '../../../src/oidb-services/contacts/fetch-friend-list-page';
|
||||
import { FetchUserProfile } from '../../../src/oidb-services/contacts/fetch-user-profile';
|
||||
import { FetchUserProfileByUid } from '../../../src/oidb-services/contacts/fetch-user-profile-by-uid';
|
||||
import { decodePublicProfile } from '../../../src/oidb-services/contacts/public-profile';
|
||||
|
||||
// Synthetic wire fixture, independent of the privilege schema: top-level tag 3;
|
||||
// body tags 2 (jump), 3 (open), 4 (closed); both entry URLs are present.
|
||||
const icons = Buffer.from(
|
||||
'1a2c1204636172641a1e08022000280032066e6f726d616c3a0664656c75786542046a756d704801220408032001',
|
||||
'hex',
|
||||
);
|
||||
const bytes = [
|
||||
{ code: 102, value: Buffer.from('') },
|
||||
{ code: 20011, value: Buffer.from('mail@example.test') },
|
||||
{ code: 20016, value: Buffer.from('') },
|
||||
{ code: 20003, value: Buffer.from('中国') },
|
||||
{ code: 20004, value: Buffer.from('省份') },
|
||||
{ code: 20020, value: Buffer.from('城市') },
|
||||
{ code: 20005, value: Buffer.from('邮编') },
|
||||
{ code: 20021, value: Buffer.from('学校') },
|
||||
{ code: 20031, value: Uint8Array.from([0, 0, 2, 29]) },
|
||||
{ code: 107, value: icons },
|
||||
];
|
||||
const numbers = [
|
||||
[20037, 0],
|
||||
[105, 0],
|
||||
[20009, 2],
|
||||
[41756, 0],
|
||||
[41757, 0],
|
||||
[42241, 0],
|
||||
] as const;
|
||||
|
||||
function sender(responseData: Uint8Array) {
|
||||
return {
|
||||
sendRawPacket: vi.fn(async () => ({
|
||||
success: true,
|
||||
gotResponse: true,
|
||||
errorCode: 0,
|
||||
errorMessage: '',
|
||||
responseData: Buffer.from(responseData),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
describe('public contact profiles', () => {
|
||||
it.each(['roster', 'uin', 'uid'])(
|
||||
'preserves presence and privilege lists through the %s wire codec',
|
||||
async (form) => {
|
||||
let profile;
|
||||
|
||||
if (form === 'roster') {
|
||||
const page = await FetchFriendListPage.invoke(
|
||||
sender(
|
||||
protobuf_encode<OidbBase<OidbSvcTrpcTcp0xFD4_1Response>>({
|
||||
body: {
|
||||
friends: [
|
||||
{
|
||||
uin: 10001,
|
||||
customGroup: 0,
|
||||
additional: [
|
||||
{
|
||||
type: 1,
|
||||
layer1: {
|
||||
properties: bytes,
|
||||
numberProperties: numbers.map(
|
||||
([key, value]) => ({ key, value }),
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
),
|
||||
{},
|
||||
);
|
||||
expect(page.entries[0]?.friend.categoryId).toBe(0);
|
||||
profile = page.entries[0]?.friend.profile;
|
||||
} else {
|
||||
const deps = sender(
|
||||
protobuf_encode<OidbBase<OidbUserInfoResponse>>({
|
||||
body: {
|
||||
body: {
|
||||
uin: 10001,
|
||||
uid: 'u_test',
|
||||
properties: {
|
||||
bytesProperties: bytes,
|
||||
numberProperties: numbers.map(([number1, number2]) => ({
|
||||
number1,
|
||||
number2,
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
const user =
|
||||
form === 'uin'
|
||||
? await FetchUserProfile.invoke(deps, { uin: 10001 })
|
||||
: await FetchUserProfileByUid.invoke(deps, { uid: 'u_test' });
|
||||
profile = user.profile;
|
||||
}
|
||||
|
||||
expect(profile).toEqual({
|
||||
sign: '',
|
||||
age: 0,
|
||||
level: 0,
|
||||
sex: 'female',
|
||||
email: 'mail@example.test',
|
||||
phoneNum: '',
|
||||
country: '中国',
|
||||
province: '省份',
|
||||
city: '城市',
|
||||
college: '学校',
|
||||
birthdayMonth: 2,
|
||||
birthdayDay: 29,
|
||||
vipFlag: false,
|
||||
svipFlag: false,
|
||||
yearVipFlag: false,
|
||||
vipLevel: 0,
|
||||
privilegeIcons: {
|
||||
jumpUrl: 'card',
|
||||
open: [
|
||||
{
|
||||
type: 2,
|
||||
level: 0,
|
||||
flag: 0,
|
||||
iconUrl: 'normal',
|
||||
deluxeIconUrl: 'deluxe',
|
||||
jumpUrl: 'jump',
|
||||
isBig: 1,
|
||||
},
|
||||
],
|
||||
closed: [{ type: 3, level: 1 }],
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it('distinguishes missing, unavailable and explicitly empty icon lists', () => {
|
||||
expect(decodePublicProfile(new Map(), new Map())).toEqual({});
|
||||
expect(decodePublicProfile(new Map([[107, Buffer.alloc(0)]]), new Map())).toEqual({});
|
||||
expect(decodePublicProfile(new Map([[107, Buffer.from([0x1a, 0])]]), new Map())).toEqual({
|
||||
privilegeIcons: { open: [], closed: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects truncated icons and invalid text without returning successful empty data', () => {
|
||||
expect(() =>
|
||||
decodePublicProfile(new Map([[107, Buffer.from([0x1a, 0xff])]]), new Map()),
|
||||
).toThrow('invalid privilege data');
|
||||
expect(() =>
|
||||
decodePublicProfile(new Map([[107, Buffer.from([0x18, 0])]]), new Map()),
|
||||
).toThrow('invalid privilege data');
|
||||
expect(() =>
|
||||
decodePublicProfile(new Map([[107, Buffer.from('1a041a020a00', 'hex')]]), new Map()),
|
||||
).toThrow('invalid privilege data');
|
||||
expect(() =>
|
||||
decodePublicProfile(new Map([[20011, Buffer.from([0xff])]]), new Map()),
|
||||
).toThrow('invalid UTF-8');
|
||||
});
|
||||
|
||||
it('rejects a profile response belonging to a different requested account', async () => {
|
||||
const deps = sender(
|
||||
protobuf_encode<OidbBase<OidbUserInfoResponse>>({ body: { body: { uin: 10002 } } }),
|
||||
);
|
||||
await expect(FetchUserProfile.invoke(deps, { uin: 10001 })).rejects.toThrow(
|
||||
'does not match',
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user