Skip to content

Commit 7fcd0bd

Browse files
committed
implement inviteUser in the cloud social provider
1 parent c8c7e36 commit 7fcd0bd

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

src/cloud/social/provider.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const ZORK_PORT = 9000;
2222
// Key under which our contacts are saved in storage.
2323
const STORAGE_KEY = 'cloud-social-contacts';
2424

25+
// Admin users can issue invites.
26+
const ADMIN_USERNAME = 'giver';
27+
const REGULAR_USERNAME = 'getter';
28+
2529
// Credentials for accessing a cloud instance.
2630
// The serialised, base64 form is distributed amongst users.
2731
// TODO: add (private) keys, for key-based auth
@@ -335,9 +339,21 @@ export class CloudSocialProvider {
335339
// social2
336340
////
337341

338-
public inviteUser = (inviteCode: string): Promise<void> => {
339-
return Promise.reject(
340-
new Error('inviteUser unimplemented'));
342+
// Returns a new invite code for the specified server.
343+
// Rejects if the user is not logged in as an admin or there
344+
// is any error executing the command.
345+
public inviteUser = (clientId: string): Promise<string> => {
346+
log.debug('inviteUser');
347+
if (!(clientId in this.clients_)) {
348+
return Promise.reject(new Error('unknown client ' + clientId));
349+
}
350+
if (this.savedContacts_[clientId].invite.user !== ADMIN_USERNAME) {
351+
return Promise.reject(new Error('user is logged in as non-admin user ' +
352+
this.savedContacts_[clientId].invite.user));
353+
}
354+
return this.clients_[clientId].then((connection: Connection) => {
355+
return connection.getBanner();
356+
});
341357
}
342358

343359
// Parses an invite code, received from uProxy in JSON format.
@@ -526,11 +542,22 @@ class Connection {
526542

527543
// Fetches the server's description, i.e. /banner.
528544
public getBanner = (): Promise<string> => {
545+
return this.exec_('cat /banner');
546+
}
547+
548+
// Issues a new invite code.
549+
public issueInvite = (): Promise<string> => {
550+
return this.exec_('sudo /issue_invite.sh');
551+
}
552+
553+
// Executes a command, fulfilling with the command's stdout
554+
// or rejecting if output is received on stderr.
555+
private exec_ = (command:string): Promise<string> => {
529556
if (this.state_ !== ConnectionState.ESTABLISHED) {
530-
return Promise.reject(new Error('can only fetch banner in ESTABLISHED state'));
557+
return Promise.reject(new Error('can only execute commands in ESTABLISHED state'));
531558
}
532559
return new Promise<string>((F, R) => {
533-
this.client_.exec('cat /banner', (e: Error, stream: ssh2.Channel) => {
560+
this.client_.exec(command, (e: Error, stream: ssh2.Channel) => {
534561
if (e) {
535562
R(e);
536563
return;
@@ -540,7 +567,7 @@ class Connection {
540567
}).stderr.on('data', function(data: Buffer) {
541568
R(new Error(data.toString()));
542569
}).on('close', function(code: any, signal: any) {
543-
log.debug('banner stream closed');
570+
log.debug('exec stream closed');
544571
});
545572
});
546573
});

0 commit comments

Comments
 (0)