fix double-requests by removing verify on connect
This commit is contained in:
parent
aa90edb142
commit
366022cebb
@ -5,7 +5,6 @@ const LOG = Logger.create(__filename, electronConsole);
|
|||||||
|
|
||||||
import { Changes, WithEquals } from './data-types';
|
import { Changes, WithEquals } from './data-types';
|
||||||
|
|
||||||
import * as uuid from 'uuid';
|
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
export enum AutoVerifierChangesType {
|
export enum AutoVerifierChangesType {
|
||||||
@ -30,8 +29,6 @@ export class AutoVerifier<T> {
|
|||||||
private verifyPromise: Promise<boolean> | null = null;
|
private verifyPromise: Promise<boolean> | null = null;
|
||||||
public trustedStatus: 'none' | 'fetching' | 'verifying' | 'verified' = 'none';
|
public trustedStatus: 'none' | 'fetching' | 'verifying' | 'verified' = 'none';
|
||||||
|
|
||||||
private verifierId: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* allows a trusted function to verify the primary function
|
* allows a trusted function to verify the primary function
|
||||||
* @param primaryFunc The primary function
|
* @param primaryFunc The primary function
|
||||||
@ -42,9 +39,8 @@ export class AutoVerifier<T> {
|
|||||||
private primaryFunc: () => Promise<T | null>,
|
private primaryFunc: () => Promise<T | null>,
|
||||||
private trustedFunc: () => Promise<T | null>,
|
private trustedFunc: () => Promise<T | null>,
|
||||||
private verifyFunc: (primaryResult: T | null, trustedResult: T | null) => Promise<boolean>,
|
private verifyFunc: (primaryResult: T | null, trustedResult: T | null) => Promise<boolean>,
|
||||||
) {
|
private name: string | null = null, // for debugging
|
||||||
this.verifierId = uuid.v4().slice(undefined, 4);
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
/** returns the changes that must be made to primaryResult given trustedResult */
|
/** returns the changes that must be made to primaryResult given trustedResult */
|
||||||
static getChanges<T extends WithEquals<T> & { id: string }>(
|
static getChanges<T extends WithEquals<T> & { id: string }>(
|
||||||
@ -125,6 +121,7 @@ export class AutoVerifier<T> {
|
|||||||
primaryFunc: () => Promise<T[] | null>,
|
primaryFunc: () => Promise<T[] | null>,
|
||||||
trustedFunc: () => Promise<T[] | null>,
|
trustedFunc: () => Promise<T[] | null>,
|
||||||
changesFunc: (changesType: AutoVerifierChangesType, changes: Changes<T>) => Promise<boolean>,
|
changesFunc: (changesType: AutoVerifierChangesType, changes: Changes<T>) => Promise<boolean>,
|
||||||
|
name: string | null = null,
|
||||||
) {
|
) {
|
||||||
return new AutoVerifier<T[]>(
|
return new AutoVerifier<T[]>(
|
||||||
primaryFunc,
|
primaryFunc,
|
||||||
@ -134,6 +131,7 @@ export class AutoVerifier<T> {
|
|||||||
const changesType = AutoVerifier.getListChangesType<T>(primaryResult, trustedResult, changes);
|
const changesType = AutoVerifier.getListChangesType<T>(primaryResult, trustedResult, changes);
|
||||||
return await changesFunc(changesType, changes);
|
return await changesFunc(changesType, changes);
|
||||||
},
|
},
|
||||||
|
name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +143,7 @@ export class AutoVerifier<T> {
|
|||||||
primaryResult: T | null,
|
primaryResult: T | null,
|
||||||
trustedResult: T | null,
|
trustedResult: T | null,
|
||||||
) => Promise<boolean>,
|
) => Promise<boolean>,
|
||||||
|
name: string | null = null,
|
||||||
) {
|
) {
|
||||||
return new AutoVerifier<T>(
|
return new AutoVerifier<T>(
|
||||||
primaryFunc,
|
primaryFunc,
|
||||||
@ -153,6 +152,7 @@ export class AutoVerifier<T> {
|
|||||||
const changesType = AutoVerifier.getSingleChangesType<T>(primaryResult, trustedResult);
|
const changesType = AutoVerifier.getSingleChangesType<T>(primaryResult, trustedResult);
|
||||||
return await changesFunc(changesType, primaryResult, trustedResult);
|
return await changesFunc(changesType, primaryResult, trustedResult);
|
||||||
},
|
},
|
||||||
|
name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ const ChannelElement: FC<ChannelElementProps> = (props: ChannelElementProps) =>
|
|||||||
setOverlay(<ChannelOverlay channel={channel} />);
|
setOverlay(<ChannelOverlay channel={channel} />);
|
||||||
}, [setOverlay, channel]);
|
}, [setOverlay, channel]);
|
||||||
|
|
||||||
|
// TODO: Restrict for permissions
|
||||||
return (
|
return (
|
||||||
<div className={baseClassName} onClick={setSelfActiveChannel}>
|
<div className={baseClassName} onClick={setSelfActiveChannel}>
|
||||||
<div className="icon">{BaseElements.TEXT_CHANNEL_ICON}</div>
|
<div className="icon">{BaseElements.TEXT_CHANNEL_ICON}</div>
|
||||||
|
@ -22,7 +22,7 @@ export default class PairVerifierFetchable extends EventEmitter<Conflictable> im
|
|||||||
public readonly fetchMessagesBeforeVerifier: AutoVerifierWithArg<Message[], PartialMessageListQuery>;
|
public readonly fetchMessagesBeforeVerifier: AutoVerifierWithArg<Message[], PartialMessageListQuery>;
|
||||||
public readonly fetchMessagesAfterVerifier: AutoVerifierWithArg<Message[], PartialMessageListQuery>;
|
public readonly fetchMessagesAfterVerifier: AutoVerifierWithArg<Message[], PartialMessageListQuery>;
|
||||||
|
|
||||||
constructor(private primary: Fetchable & Lackable, private trusted: Fetchable & Ensurable) {
|
constructor(private primary: Fetchable & Lackable, private trusted: Fetchable & Ensurable, private name: string | null = null) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (trusted instanceof PairVerifierFetchable) {
|
if (trusted instanceof PairVerifierFetchable) {
|
||||||
@ -239,7 +239,6 @@ export default class PairVerifierFetchable extends EventEmitter<Conflictable> im
|
|||||||
}
|
}
|
||||||
|
|
||||||
unverify() {
|
unverify() {
|
||||||
// lOG.debug('unverifying all');
|
|
||||||
this.fetchMetadataVerifier.unverify();
|
this.fetchMetadataVerifier.unverify();
|
||||||
this.fetchMembersVerifier.unverify();
|
this.fetchMembersVerifier.unverify();
|
||||||
this.fetchChannelsVerifier.unverify();
|
this.fetchChannelsVerifier.unverify();
|
||||||
@ -250,10 +249,6 @@ export default class PairVerifierFetchable extends EventEmitter<Conflictable> im
|
|||||||
this.fetchMessagesRecentVerifier.unverifyAll();
|
this.fetchMessagesRecentVerifier.unverifyAll();
|
||||||
this.fetchMessagesBeforeVerifier.unverifyAll();
|
this.fetchMessagesBeforeVerifier.unverifyAll();
|
||||||
this.fetchMessagesAfterVerifier.unverifyAll();
|
this.fetchMessagesAfterVerifier.unverifyAll();
|
||||||
|
|
||||||
if (this.trusted instanceof PairVerifierFetchable) {
|
|
||||||
this.trusted.unverify();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchMetadata(): Promise<GuildMetadata | null> {
|
async fetchMetadata(): Promise<GuildMetadata | null> {
|
||||||
|
@ -59,14 +59,15 @@ export default class CombinedGuild
|
|||||||
this.personalDBGuild = new PersonalDBGuild(personalDB, this.id, this.memberId);
|
this.personalDBGuild = new PersonalDBGuild(personalDB, this.id, this.memberId);
|
||||||
this.socketGuild = new SocketGuild(socket, socketVerifier);
|
this.socketGuild = new SocketGuild(socket, socketVerifier);
|
||||||
|
|
||||||
const diskSocket = new PairVerifierFetchable(this.personalDBGuild, this.socketGuild);
|
const diskSocket = new PairVerifierFetchable(this.personalDBGuild, this.socketGuild, 'Disk -> Socket');
|
||||||
const ramDiskSocket = new PairVerifierFetchable(this.ramGuild, diskSocket);
|
const ramDiskSocket = new PairVerifierFetchable(this.ramGuild, diskSocket, 'RAM -> Disk');
|
||||||
|
|
||||||
|
// TODO: I think this unverify is causing the RARE ALERTs
|
||||||
|
// do we need to unverify on connect? or just disconnect?
|
||||||
// connect/Disconnect
|
// connect/Disconnect
|
||||||
this.socketGuild.on('connect', () => {
|
this.socketGuild.on('connect', () => {
|
||||||
LOG.info(`g#${this.id} connected`);
|
LOG.info(`g#${this.id} connected`);
|
||||||
diskSocket.unverify();
|
ramDiskSocket.unverify(); // make sure to query the disk-socket AutoVerifier again
|
||||||
ramDiskSocket.unverify();
|
|
||||||
this.emit('connect');
|
this.emit('connect');
|
||||||
});
|
});
|
||||||
this.socketGuild.on('disconnect', async () => {
|
this.socketGuild.on('disconnect', async () => {
|
||||||
|
@ -53,7 +53,7 @@ export default class SocketVerifier extends EventEmitter<{ verified: () => void
|
|||||||
}
|
}
|
||||||
this.memberId = memberId;
|
this.memberId = memberId;
|
||||||
this.isVerified = true;
|
this.isVerified = true;
|
||||||
LOG.debug(`verified as u#${memberId}`);
|
LOG.debug(`verified as u#${memberId.slice(0, 4)}`);
|
||||||
resolve(memberId);
|
resolve(memberId);
|
||||||
this.emit('verified');
|
this.emit('verified');
|
||||||
});
|
});
|
||||||
|
@ -67,7 +67,7 @@ export default class DB {
|
|||||||
// eslint-disable-next-line newline-per-chained-call
|
// eslint-disable-next-line newline-per-chained-call
|
||||||
LOG.silly(
|
LOG.silly(
|
||||||
`searching for public key (der hash: ${LOG.inspect(
|
`searching for public key (der hash: ${LOG.inspect(
|
||||||
crypto.createHash('sha256').update(der).digest().toString('hex'),
|
crypto.createHash('sha256').update(der).digest().toString('hex').slice(0, 8),
|
||||||
)})`,
|
)})`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -127,7 +127,6 @@ function bindEvent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//lOG.debug(`c#${client.id}: ${name}`);
|
|
||||||
try {
|
try {
|
||||||
await handler(...args);
|
await handler(...args);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -139,7 +138,7 @@ function bindEvent(
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof SignatureError) {
|
if (e instanceof SignatureError) {
|
||||||
LOG.warn(`c#${client.id}: ${name} request does not match expected signature`, {
|
LOG.warn(`c#${client.id.slice(0, 4)}: ${name} request does not match expected signature`, {
|
||||||
signature,
|
signature,
|
||||||
args,
|
args,
|
||||||
msg: e.message,
|
msg: e.message,
|
||||||
@ -147,7 +146,7 @@ function bindEvent(
|
|||||||
// do not respond to requests with invalid signatures
|
// do not respond to requests with invalid signatures
|
||||||
} else if (e instanceof EventError) {
|
} else if (e instanceof EventError) {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
`c#${client.id}: ${e.message}${e.extended_message ? ' / ' + e.extended_message : ''}`,
|
`c#${client.id.slice(0, 4)}: ${e.message}${e.extended_message ? ' / ' + e.extended_message : ''}`,
|
||||||
e.cause,
|
e.cause,
|
||||||
);
|
);
|
||||||
respond(e.message);
|
respond(e.message);
|
||||||
@ -204,7 +203,7 @@ function bindRegistrationEvents(io: socketio.Server, client: socketio.Socket): v
|
|||||||
const member = await DB.getMember(guildId, memberId);
|
const member = await DB.getMember(guildId, memberId);
|
||||||
const meta = await DB.getGuild(guildId);
|
const meta = await DB.getGuild(guildId);
|
||||||
|
|
||||||
LOG.info(`c#${client.id}: registered with t#${token} as u#${member.id} / ${member.display_name}`);
|
LOG.info(`c#${client.id.slice(0, 4)}: registered with t#${token} as u#${member.id} / ${member.display_name}`);
|
||||||
|
|
||||||
respond(null, member, meta);
|
respond(null, member, meta);
|
||||||
|
|
||||||
@ -245,7 +244,7 @@ function bindChallengeVerificationEvents(io: socketio.Server, client: socketio.S
|
|||||||
throw new EventError('unauthorized public key', e as Error);
|
throw new EventError('unauthorized public key', e as Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.debug(`c#${client.id}: challenging for u#${identity.memberId?.slice(0, 4)}`);
|
LOG.debug(`c#${client.id.slice(0, 4)}: challenging for u#${identity.memberId?.slice(0, 4)}`);
|
||||||
|
|
||||||
if (connected.find(i => i.memberId === identity.memberId && i.verified)) {
|
if (connected.find(i => i.memberId === identity.memberId && i.verified)) {
|
||||||
throw new EventError('member already connected');
|
throw new EventError('member already connected');
|
||||||
@ -315,10 +314,10 @@ function bindChallengeVerificationEvents(io: socketio.Server, client: socketio.S
|
|||||||
.map((privilege: string) => guildPrivilegeRoomName(identity.guildId as string, privilege))
|
.map((privilege: string) => guildPrivilegeRoomName(identity.guildId as string, privilege))
|
||||||
: [],
|
: [],
|
||||||
);
|
);
|
||||||
LOG.debug(`c#${client.id} joining ${rooms.join(', ')}`);
|
LOG.debug(`c#${client.id.slice(0, 4)} joining g#[${rooms.map(room => room.slice(0, 4)).join(', ')}]`);
|
||||||
client.join(rooms);
|
client.join(rooms);
|
||||||
|
|
||||||
LOG.info(`c#${client.id}: verified as g#${identity.guildId} u#${identity.memberId?.slice(0, 4)}`);
|
LOG.info(`c#${client.id.slice(0, 4)}: verified as g#${identity.guildId.slice(0, 4)} u#${identity.memberId?.slice(0, 4)}`);
|
||||||
respond(null, identity.memberId);
|
respond(null, identity.memberId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -753,7 +752,7 @@ function bindActionEvents(io: socketio.Server, client: socketio.Socket, identity
|
|||||||
if (!identity.memberId) throw new EventError('identity no memberId');
|
if (!identity.memberId) throw new EventError('identity no memberId');
|
||||||
|
|
||||||
if (avatarBuff.length > MAX_AVATAR_SIZE) {
|
if (avatarBuff.length > MAX_AVATAR_SIZE) {
|
||||||
LOG.warn(`c#${client.id}: avatar too large`);
|
LOG.warn(`c#${client.id.slice(0, 4)}: avatar too large`);
|
||||||
respond('buffer too large');
|
respond('buffer too large');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -825,7 +824,7 @@ function bindFetchEvents(client: socketio.Socket, identity: IIdentity): void {
|
|||||||
if (!identity.guildId) throw new EventError('identity no guildId');
|
if (!identity.guildId) throw new EventError('identity no guildId');
|
||||||
if (!identity.memberId) throw new EventError('identity no memberId');
|
if (!identity.memberId) throw new EventError('identity no memberId');
|
||||||
LOG.info(
|
LOG.info(
|
||||||
`u#${identity.memberId?.slice(0, 4)}: fetching recent messages for ch#${channelId} number: ${number}`,
|
`u#${identity.memberId?.slice(0, 4)}: fetching recent messages for ch#${channelId.slice(0, 4)} number: ${number}`,
|
||||||
);
|
);
|
||||||
const messages = await DB.getMessagesRecent(identity.guildId, channelId, number);
|
const messages = await DB.getMessagesRecent(identity.guildId, channelId, number);
|
||||||
respond(null, messages);
|
respond(null, messages);
|
||||||
@ -929,7 +928,7 @@ function bindFetchEvents(client: socketio.Socket, identity: IIdentity): void {
|
|||||||
|
|
||||||
export function bindSocketEvents(io: socketio.Server): void {
|
export function bindSocketEvents(io: socketio.Server): void {
|
||||||
io.on('connection', client => {
|
io.on('connection', client => {
|
||||||
LOG.info(`c#${client.id}: connected`);
|
LOG.info(`c#${client.id.slice(0, 4)}: connected`);
|
||||||
|
|
||||||
const identity: IIdentity = {
|
const identity: IIdentity = {
|
||||||
guildId: null,
|
guildId: null,
|
||||||
@ -953,7 +952,7 @@ export function bindSocketEvents(io: socketio.Server): void {
|
|||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
if (identity.verified) {
|
if (identity.verified) {
|
||||||
LOG.info(`c#${client.id}: disconnected (was u#${identity.memberId?.slice(0, 4)})`);
|
LOG.info(`c#${client.id.slice(0, 4)}: disconnected (was u#${identity.memberId?.slice(0, 4)})`);
|
||||||
(async () => {
|
(async () => {
|
||||||
if (!identity.guildId || !identity.memberId) return;
|
if (!identity.guildId || !identity.memberId) return;
|
||||||
try {
|
try {
|
||||||
@ -963,7 +962,7 @@ export function bindSocketEvents(io: socketio.Server): void {
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
} else {
|
} else {
|
||||||
LOG.info(`c#${client.id}: disconnected (was unverified)`);
|
LOG.info(`c#${client.id.slice(0, 4)}: disconnected (was unverified)`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user