-
-
Notifications
You must be signed in to change notification settings - Fork 414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Keynames for Nick reservation #423
Conversation
Two things bug me about this:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this!
Wrote some ideas for changes, I think we're on the right track and hopefully these changes will address your concerns too.
func (a *Auth) SetKeynamesMode(value bool) { | ||
a.settingsMu.Lock() | ||
defer a.settingsMu.Unlock() | ||
a.keynamesMode = value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to track the mode on the Auth struct if we can just avoid populating it when the flag is off?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really. I was just following existing convention for the allowlistMode
@@ -168,6 +192,17 @@ func (a *Auth) Op(key ssh.PublicKey, d time.Duration) { | |||
} else { | |||
a.ops.Set(authItem) | |||
} | |||
|
|||
// nick registration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of pulling this out into a helper that can be run independently? Something like func parseAuthComment(comment string) (nick string, prefix string)
This would also be a good place to parse out the @...
part of the nick and only use the first part, which would address your second concern. :)
(That is, foo@bar
would become foo
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That occurred to me the instant I copied and pasted between these two functions, naturally :)
wrt to @
, I actually want to keep the @host
suffix. I tend to generate keys on each account on each host, rather than copying them around, so using them to identify accounts on particular hosts, rather than just individual people, seems natural to me.
@@ -378,6 +387,60 @@ func (h *Host) InitCommands(c *chat.Commands) { | |||
}, | |||
}) | |||
|
|||
c.Add(chat.Command{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I'd much prefer to keep the /nick
command in the chat
module.
Could we do the extra checking inside the room.Rename
function?
Also preferably the Room shouldn't know about details of the Host's implementation, so ideally the Host would pass in something like a CheckAvailableID(string) error
interface to the Room, and that can do the checking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I moved /nick to host.go was so that the Command was able to get a reference to an Auth instance (through the host), which is where the reservation data lives.
At first I saw that Host is an extension of a Room, and tried a type assertion on it, but that didn't seem to work. Perhaps there's a way to do that without moving the nick Command. My Go knowledge isn't the best, so pointers welcome!
if h.auth.keynamesMode { | ||
identity, identified := member.Identifier.(*Identity) | ||
if identified { | ||
identity.SetSymbol(strings.Replace(identity.symbol, "✓", "", -1 )) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't hardcode symbols here. If we want a checkmark symbol for registered names, we can have them in the key comment, right?
We can have cases where people wish to reserve names but not want to have a checkmark, or maybe a checkmark is earned in some other way on some servers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given how contentious this issue has been, the symbol prefix may also be the wrong place to do this.
Instead, what if we added a field to the /whois listing that displays the ssh key comment, in it's entirety?
The situation I'm trying to avoid by enforcing the symbol appearance is one where a user claims their nick is reserved, when it isn't. Other non-admin users should be able to depend on it, so long as they can trust the operators (who can still assign any symbol string with /rename
).
If we put this in a /whois
field, instead, other users will always have access to that, and will always be able to depend on it, whether the user has a registered nick or not. I can then undo all the symbol-setting business; operators can continue to /rename
with any symbols they want, and future developers can brainstorm and implement new features there as they please.
oldID := member.ID() | ||
newID := sanitize.Name(args[1]) | ||
|
||
// check nick registration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think we need this here, right? /rename
can only be called by admins, and it should override any default behaviour anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two levels of authority - the users in the admin list (operators), including those granted ops by other ops, and the folks who have write privileges to the admin and allowlist files. I thought it more trustworthy to limit the class of people who can override the nick reservations, to maximize the amount trust users could put in the system.
name := h.auth.Keyname(id.PublicKey()) | ||
if len(name) >0 { | ||
id.SetName(name) | ||
id.SetSymbol("✓") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need to hard-code symbols, but rather load them from the comment.
@@ -38,6 +38,7 @@ type Options struct { | |||
Version bool `long:"version" description:"Print version and exit."` | |||
Allowlist string `long:"allowlist" description:"Optional file of public keys who are allowed to connect."` | |||
Whitelist string `long:"whitelist" dexcription:"Old name for allowlist option"` | |||
Keynames bool `long:"keynames" description:"Reserve usernames by appending them (after a space) to their keys in the admin or allowlist files."` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe ReserveNames
and reserve-names
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--reserve-names
does sound better - it says more directly what it does. --keynames
says more about how it's done. I'll change that.
@@ -61,9 +62,12 @@ type Auth struct { | |||
banned *set.Set | |||
allowlist *set.Set | |||
ops *set.Set | |||
keynamesByFingerprint map[string]string | |||
fingerprintsByKeyname map[string]string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need fingerprintsByKeyname
? I don't think we're actually using it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see Auth.Keyname() and Auth.KeynameFingerprint(). The former is used to determine what registereed name to assign a newly-connected user, based on their fingerprint. The latter is used to find the fingerprint that a nick may be registered to, to compare it with the fingerprint of the user's key in /nick
and /rename
.
I suppose we could just build one map at launch, then implement one or the other function to iterate over the same map instead, instead of building two inverted maps to do separate lookups with.
@@ -61,9 +62,12 @@ type Auth struct { | |||
banned *set.Set | |||
allowlist *set.Set | |||
ops *set.Set | |||
keynamesByFingerprint map[string]string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better to make this fingerprintComments
, and store the comment section of the fingerprint altogether here? This way we can extract both the name and the symbol later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intent was to just parse the keyname (first word) from the comment, and drop the rest. I'd rather leave future features to future developers.
I've incorporated most of the changes discussed here to #424 . I'll leave this one open for the moment, but I think both of us will like the new one better. |
This pr supersedes and replaces #420
So here we have a full-blown chat nick reservation implementation.
Chat nicks are reserved for users by passing the
--keynames
option to ssh-chat at startup, and placing the desired nickname at the end of the public key line (separated by a space) in the allow list or admin key files. This is the "comment" field is traditionally filled out with$user@$host
information when OpenSSH generates an ssh keypair. This makes the public key file suitable for simply copying and pasting into the allowlist or admin files, line for line, in order to reserve usernames. Only the first word of the comment field is used for the reserved nick.When a user with a reserved nick connects, they are automatically assigned the username assigned to their key along with a checkmark symbol prefix to indicate that their key fingerprint is verified by the server.
The
/nick
and/rename
commands have been reimplemented to prevent users from receiving reserved nicks unless their ssh key matches that recorded in the reservation lists.