Skip to content

Commit e15f080

Browse files
committed
Merge pull request #361 from uProxy/dborkan-cloud-invites
Cleanup cloud invite code to not require SSH access
2 parents 181887c + 2514331 commit e15f080

File tree

1 file changed

+20
-45
lines changed

1 file changed

+20
-45
lines changed

src/cloud/social/provider.ts

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,22 @@ 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-
2925
// Timeout for establishing an SSH connection.
3026
const CONNECT_TIMEOUT_MS = 10000;
3127

3228
// Credentials for accessing a cloud instance.
3329
// The serialised, base64 form is distributed amongst users.
34-
// TODO: add (private) keys, for key-based auth
3530
interface Invite {
3631
// Hostname or IP of the cloud instance.
3732
// This is the host on which sshd is running, so it should
3833
// be directly accessible from the client.
39-
host?: string;
34+
host: string;
4035
// Username.
41-
user?: string;
42-
// Password.
43-
pass?: string;
36+
user: string;
4437
// Private key, base64-encoded.
45-
key?: string;
38+
key: string;
39+
// True iff uProxy has root access on the server, i.e. uProxy deployed it.
40+
isAdmin?: boolean;
4641
}
4742

4843
// Type of the object placed, in serialised form, in storage
@@ -130,11 +125,9 @@ function makeClientState(address: string): freedom.Social.ClientState {
130125
// the status field since remote-user.ts#update will use FRIEND as a default.
131126
function makeUserProfile(
132127
address: string,
133-
username :string): freedom.Social.UserProfile {
134-
var status = UserStatus.CLOUD_INSTANCE_SHARED_WITH_LOCAL;
135-
if (username === ADMIN_USERNAME) {
136-
status = UserStatus.CLOUD_INSTANCE_CREATED_BY_LOCAL;
137-
}
128+
isAdmin ?:boolean): freedom.Social.UserProfile {
129+
var status = isAdmin ? UserStatus.CLOUD_INSTANCE_CREATED_BY_LOCAL :
130+
UserStatus.CLOUD_INSTANCE_SHARED_WITH_LOCAL;
138131
return {
139132
userId: address,
140133
name: address,
@@ -146,8 +139,7 @@ function makeUserProfile(
146139
//
147140
// Intended for use with the run_cloud.sh script in the uproxy-docker
148141
// repo, which will spin up the expected configuration:
149-
// - an SSH server running on port 5000, with an account named
150-
// "giver" having the password "giver"
142+
// - an SSH server running on port 5000, with an account named "giver"
151143
// - a Zork instance, accessible from the SSH server at the
152144
// hostname "zork"
153145
//
@@ -180,7 +172,7 @@ export class CloudSocialProvider {
180172
// in the contacts list.
181173
private notifyOfUser_ = (invite: Invite, description?: string) => {
182174
this.dispatchEvent_('onUserProfile',
183-
makeUserProfile(invite.host, invite.user));
175+
makeUserProfile(invite.host, invite.isAdmin));
184176

185177
var clientState = makeClientState(invite.host);
186178
this.dispatchEvent_('onClientState', clientState);
@@ -363,26 +355,19 @@ export class CloudSocialProvider {
363355
// social2
364356
////
365357

366-
// Returns a new invite code for the specified server.
367-
// Rejects if the user is not logged in as an admin or there
368-
// is any error executing the command.
369-
// TODO: typings for invite codes
370-
public inviteUser = (clientId: string): Promise<Object> => {
358+
// Returns the invite code for the specified server.
359+
public inviteUser = (host: string): Promise<Object> => {
371360
log.debug('inviteUser');
372-
if (!(clientId in this.savedContacts_)) {
373-
return Promise.reject({
374-
message: 'unknown cloud instance ' + clientId
375-
});
376-
}
377-
if (this.savedContacts_[clientId].invite.user !== ADMIN_USERNAME) {
361+
if (!(host in this.savedContacts_)) {
378362
return Promise.reject({
379-
message: 'user is logged in as non-admin user ' +
380-
this.savedContacts_[clientId].invite.user
363+
message: 'unknown cloud instance ' + host
381364
});
382365
}
383-
return this.reconnect_(this.savedContacts_[clientId].invite).then(
384-
(connection: Connection) => {
385-
return connection.issueInvite();
366+
const invite = this.savedContacts_[host].invite;
367+
return Promise.resolve(<Invite>{
368+
host: invite.host,
369+
user: invite.user,
370+
key: invite.key
386371
});
387372
}
388373

@@ -461,9 +446,6 @@ class Connection {
461446

462447
if (this.invite_.key) {
463448
connectConfig['privateKey'] = new Buffer(this.invite_.key, 'base64');
464-
} else {
465-
log.warn('using password-based auth, support will be removed soon!');
466-
connectConfig['password'] = this.invite_.pass;
467449
}
468450

469451
return new Promise<void>((F, R) => {
@@ -527,7 +509,7 @@ class Connection {
527509
});
528510
}).on('error', (e: Error) => {
529511
// This occurs when:
530-
// - user supplies the wrong username or password
512+
// - user supplies the wrong credentials
531513
// - host cannot be reached, e.g. non-existant hostname
532514
log.warn('%1: connection error: %2', this.name_, e);
533515
this.setState_(ConnectionState.TERMINATED);
@@ -564,13 +546,6 @@ class Connection {
564546
return this.exec_('cat /banner');
565547
}
566548

567-
// Returns a base64-decoded, deserialised invite code.
568-
public issueInvite = (): Promise<Object> => {
569-
return this.exec_('sudo /issue_invite.sh').then((inviteCode: string) => {
570-
return JSON.parse(new Buffer(inviteCode, 'base64').toString());
571-
});
572-
}
573-
574549
// Executes a command, fulfilling with the first line of the command's
575550
// output on stdout or rejecting if any output is received on stderr.
576551
// TODO: There is a close event with a return code which

0 commit comments

Comments
 (0)