80 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			80 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# welcome command
 | 
						|
 | 
						|
this command is used to exchange a town invite token for a user account. it is
 | 
						|
responsible for:
 | 
						|
 | 
						|
1. accepting and validating an invite token generated by the `review` command
 | 
						|
2. accepting and validating a new user's username choice (ie enforcing rules and checking for dupes)
 | 
						|
3. accepting and validating a user's email for use in account recovery (defaulting to an email embedded in the invite token)
 | 
						|
4. accepting and validating a display name (PUT OFF)
 | 
						|
5. Confirming that a user agrees to our CoC
 | 
						|
6. accepting and validating a user's public ssh key
 | 
						|
 | 
						|
upon receipt of these things a user account is created. if it fails, the user
 | 
						|
is told about the failure and told to email root@tilde.town for guidance; us
 | 
						|
admins get a local mail about the problem.
 | 
						|
 | 
						|
upon successful creation, `welcome` prints a message on STDOUT suggesting how to log in then quits.
 | 
						|
 | 
						|
It is risky to let `welcome` create users but no riskier at a high level than the Django admin we had. I can re-use the sudoers trick I did there for the `welcome` user.
 | 
						|
 | 
						|
## an invite token
 | 
						|
 | 
						|
an invite token consists of two pieces that are then base64 encoded. the first piece is a random string of 30 characters (alphanumeric and symbols except space) and the second is an email address the invite was sent to; they are separated by a space.
 | 
						|
 | 
						|
## sudoers config
 | 
						|
 | 
						|
something like:
 | 
						|
 | 
						|
```
 | 
						|
welcome ALL=(ALL)NOPASSWD:/usr/sbin/adduser,/usr/sbin/usermod,/town/bin/createkeyfile,/town/bin/generate_welcome_present.sh,/town/bin/registeruser
 | 
						|
```
 | 
						|
 | 
						|
I'd like to consolidate adduser/usermod calls into a single "createuser" helper. I'd also like to move the welcome present generation into `welcome`. TODO.
 | 
						|
 | 
						|
## user creation flow
 | 
						|
 | 
						|
once we accept what we need from the user accepting an invite, the flow looks like:
 | 
						|
 | 
						|
1. create user account
 | 
						|
  a. run `adduser`, set shell and displayname
 | 
						|
  b. add user to town group
 | 
						|
2. write authorized keys
 | 
						|
  a. create `~/.ssh`
 | 
						|
  b. write `~/.ssh/authorized_keys2` and put their key in there
 | 
						|
  c. write blank `~/.ssh/authorized_keys` with note about adding custom keys
 | 
						|
3. generate welcome gift
 | 
						|
4. alert hooks (more of a future idea; but it would be nice to have a "WELCOME NEW USER!" in the mailing list / IRC / etc)
 | 
						|
 | 
						|
## creating keyfiles
 | 
						|
 | 
						|
A frustrating hurdle is that `welcome`, just like `ttadmin`, has to write a keyfile that is perms 600 for the new user. This is annoying as shit and requires running `sudo` as the new user. In the old python code:
 | 
						|
 | 
						|
```python
 | 
						|
def write_authorized_keys(self):
 | 
						|
    # Write out authorized_keys file
 | 
						|
    # Why is this a call out to a python script? There's no secure way with
 | 
						|
    # sudoers to allow this code to write to a file; if this code was to be
 | 
						|
    # compromised, the ability to write arbitrary files with sudo is a TKO.
 | 
						|
    # By putting the ssh key file creation into its own script, we can just
 | 
						|
    # give sudo access for that one command to this code.
 | 
						|
    #
 | 
						|
    # We could put the other stuff from here into that script and then only
 | 
						|
    # grant sudo for the script, but then we're moving code out of this
 | 
						|
    # virtual-env contained, maintainable thing into a script. it's my
 | 
						|
    # preference to have the script be as minimal as possible.
 | 
						|
    with TemporaryFile(dir="/tmp") as fp:
 | 
						|
        fp.write(self.generate_authorized_keys().encode('utf-8'))
 | 
						|
        fp.seek(0)
 | 
						|
        error = _guarded_run(['sudo',
 | 
						|
                              '--user={}'.format(self.username),
 | 
						|
                              '/town/src/tildetown-admin/scripts/create_keyfile.py',
 | 
						|
                              self.username],
 | 
						|
                             stdin=fp)
 | 
						|
        if error:
 | 
						|
            logger.error(error)
 | 
						|
 | 
						|
```
 | 
						|
 | 
						|
this warrants porting `create_keyfile.py` to a new Go program that can live at `/town/bin/create_keyfile` or wherever.
 |