// resetAuth is called to reset the authorization on an MDServer // connection. func (md *MDServerRemote) resetAuth(ctx context.Context, c keybase1.MetadataClient) (int, error) { md.log.Debug("MDServerRemote: resetAuth called") isAuthenticated := false defer func() { md.authenticatedMtx.Lock() md.isAuthenticated = isAuthenticated md.authenticatedMtx.Unlock() }() _, _, err := md.config.KBPKI().GetCurrentUserInfo(ctx) if err != nil { md.log.Debug("MDServerRemote: User logged out, skipping resetAuth") return MdServerDefaultPingIntervalSeconds, NoCurrentSessionError{} } challenge, err := c.GetChallenge(ctx) if err != nil { md.log.Warning("MDServerRemote: challenge request error: %v", err) return 0, err } md.log.Debug("MDServerRemote: received challenge") // get a new signature signature, err := md.authToken.Sign(ctx, challenge) if err != nil { md.log.Warning("MDServerRemote: error signing authentication token: %v", err) return 0, err } md.log.Debug("MDServerRemote: authentication token signed") // authenticate pingIntervalSeconds, err := c.Authenticate(ctx, signature) if err != nil { md.log.Warning("MDServerRemote: authentication error: %v", err) return 0, err } md.log.Debug("MDServerRemote: authentication successful; ping interval: %ds", pingIntervalSeconds) isAuthenticated = true md.authenticatedMtx.Lock() if !md.isAuthenticated { defer func() { // request a list of folders needing rekey action if err := md.getFoldersForRekey(ctx, c); err != nil { md.log.Warning("MDServerRemote: getFoldersForRekey failed with %v", err) } md.log.Debug("MDServerRemote: requested list of folders for rekey") }() } // Need to ensure that any conflicting thread gets the updated value md.isAuthenticated = true md.authenticatedMtx.Unlock() return pingIntervalSeconds, nil }
// getFoldersForRekey registers to receive updates about folders needing rekey actions. func (md *MDServerRemote) getFoldersForRekey(ctx context.Context, client keybase1.MetadataClient) error { // get this device's crypt public key cryptKey, err := md.config.KBPKI().GetCurrentCryptPublicKey(ctx) if err != nil { return err } return client.GetFoldersForRekey(ctx, cryptKey.kid) }
// OnConnect implements the ConnectionHandler interface. func (md *MDServerRemote) OnConnect(ctx context.Context, conn *Connection, client keybase1.GenericClient, server *rpc.Server) error { md.log.Debug("MDServerRemote: OnConnect called with a new connection") // request a challenge -- using md.client here would cause problematic recursion. c := keybase1.MetadataClient{Cli: cancelableClient{client}} challenge, err := c.GetChallenge(ctx) if err != nil { md.log.Warning("MDServerRemote: challenge request error: %v", err) return err } md.log.Debug("MDServerRemote: received challenge") // get a new signature signature, err := md.authToken.Sign(ctx, challenge) if err != nil { md.log.Warning("MDServerRemote: error signing authentication token: %v", err) return err } md.log.Debug("MDServerRemote: authentication token signed") // authenticate pingIntervalSeconds, err := c.Authenticate(ctx, signature) if err != nil { md.log.Warning("MDServerRemote: authentication error: %v", err) return err } md.log.Debug("MDServerRemote: authentication successful; ping interval: %ds", pingIntervalSeconds) // we'll get replies asynchronously as to not block the connection // for doing other active work for the user. they will be sent to // the FolderNeedsRekey handler. if err := server.Register(keybase1.MetadataUpdateProtocol(md)); err != nil { if _, ok := err.(rpc.AlreadyRegisteredError); !ok { return err } } // request a list of folders needing rekey action if err := md.getFoldersForRekey(ctx, c); err != nil { md.log.Warning("MDServerRemote: getFoldersForRekey failed with %v", err) } md.log.Debug("MDServerRemote: requested list of folders for rekey") // start pinging md.resetPingTicker(pingIntervalSeconds) return nil }