@@ -22,6 +22,10 @@ const ZORK_PORT = 9000;
2222// Key under which our contacts are saved in storage.
2323const 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