Add api-key based login
This commit is contained in:
parent
f36f99456b
commit
5af078092e
@ -51,7 +51,11 @@ func sync(ctx context.Context, vault *vault.Vault, cfg *config.Config) bool {
|
|||||||
token, err := cfg.GetToken()
|
token, err := cfg.GetToken()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if token.AccessToken != "" {
|
if token.AccessToken != "" {
|
||||||
bitwarden.RefreshToken(ctx, cfg)
|
refreshed := bitwarden.RefreshToken(ctx, cfg)
|
||||||
|
if !refreshed {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
userSymmetricKey, err := cfg.GetUserSymmetricKey()
|
userSymmetricKey, err := cfg.GetUserSymmetricKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
@ -83,10 +87,17 @@ func ensureIsNotLocked(action Action) Action {
|
|||||||
ctx1 := context.Background()
|
ctx1 := context.Background()
|
||||||
success := sync(ctx1, vault, cfg)
|
success := sync(ctx1, vault, cfg)
|
||||||
if err != nil || !success {
|
if err != nil || !success {
|
||||||
|
if err != nil {
|
||||||
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||||
|
Success: false,
|
||||||
|
Message: "Could not sync vault",
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
systemauth.CreatePinSession(*ctx)
|
systemauth.CreatePinSession(*ctx)
|
||||||
|
@ -55,6 +55,38 @@ func handleSetNotifications(request messages.IPCMessage, cfg *config.Config, vau
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleSetClientID(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
||||||
|
clientID := messages.ParsePayload(request).(messages.SetClientIDRequest).Value
|
||||||
|
cfg.SetClientID(clientID)
|
||||||
|
err = cfg.WriteConfig()
|
||||||
|
if err != nil {
|
||||||
|
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||||
|
Success: false,
|
||||||
|
Message: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||||
|
Success: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleSetClientSecret(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
||||||
|
clientSecret := messages.ParsePayload(request).(messages.SetClientSecretRequest).Value
|
||||||
|
cfg.SetClientSecret(clientSecret)
|
||||||
|
err = cfg.WriteConfig()
|
||||||
|
if err != nil {
|
||||||
|
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||||
|
Success: false,
|
||||||
|
Message: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||||
|
Success: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func handleGetRuntimeConfig(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
func handleGetRuntimeConfig(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
||||||
return messages.IPCMessageFromPayload(messages.GetRuntimeConfigResponse{
|
return messages.IPCMessageFromPayload(messages.GetRuntimeConfigResponse{
|
||||||
UseMemguard: cfg.ConfigFile.RuntimeConfig.UseMemguard,
|
UseMemguard: cfg.ConfigFile.RuntimeConfig.UseMemguard,
|
||||||
@ -68,4 +100,6 @@ func init() {
|
|||||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetApiURLRequest{}), handleSetApiURL)
|
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetApiURLRequest{}), handleSetApiURL)
|
||||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetNotificationsURLRequest{}), handleSetNotifications)
|
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetNotificationsURLRequest{}), handleSetNotifications)
|
||||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.GetRuntimeConfigRequest{}), handleGetRuntimeConfig)
|
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.GetRuntimeConfigRequest{}), handleGetRuntimeConfig)
|
||||||
|
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetClientIDRequest{}), handleSetClientID)
|
||||||
|
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetClientSecretRequest{}), handleSetClientSecret)
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,9 @@ func handleLogin(msg messages.IPCMessage, cfg *config.Config, vault *vault.Vault
|
|||||||
var masterKey crypto.MasterKey
|
var masterKey crypto.MasterKey
|
||||||
var masterpasswordHash string
|
var masterpasswordHash string
|
||||||
|
|
||||||
if req.Passwordless {
|
if secret, err := cfg.GetClientSecret(); err == nil && secret != "" {
|
||||||
|
token, masterKey, masterpasswordHash, err = bitwarden.LoginWithApiKey(ctx, req.Email, cfg, vault)
|
||||||
|
} else if req.Passwordless {
|
||||||
token, masterKey, masterpasswordHash, err = bitwarden.LoginWithDevice(ctx, req.Email, cfg, vault)
|
token, masterKey, masterpasswordHash, err = bitwarden.LoginWithDevice(ctx, req.Email, cfg, vault)
|
||||||
} else {
|
} else {
|
||||||
token, masterKey, masterpasswordHash, err = bitwarden.LoginWithMasterpassword(ctx, req.Email, cfg, vault)
|
token, masterKey, masterpasswordHash, err = bitwarden.LoginWithMasterpassword(ctx, req.Email, cfg, vault)
|
||||||
|
@ -43,6 +43,10 @@ type LoginResponseToken struct {
|
|||||||
TokenType string `json:"token_type"`
|
TokenType string `json:"token_type"`
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
|
Kdf int `json:"Kdf"`
|
||||||
|
KdfIterations int `json:"KdfIterations"`
|
||||||
|
KdfMemory int `json:"KdfMemory"`
|
||||||
|
KdfParallelism int `json:"KdfParallelism"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -64,6 +68,52 @@ func deviceType() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoginWithApiKey(ctx context.Context, email string, cfg *config.Config, vault *vault.Vault) (LoginResponseToken, crypto.MasterKey, string, error) {
|
||||||
|
clientID, err := cfg.GetClientID()
|
||||||
|
if err != nil {
|
||||||
|
notify.Notify("Goldwarden", fmt.Sprintf("Could not get client ID: %v", err), "", func() {})
|
||||||
|
return LoginResponseToken{}, crypto.MasterKey{}, "", fmt.Errorf("could not get client ID: %v", err)
|
||||||
|
}
|
||||||
|
clientSecret, err := cfg.GetClientSecret()
|
||||||
|
if err != nil {
|
||||||
|
notify.Notify("Goldwarden", fmt.Sprintf("Could not get client secret: %v", err), "", func() {})
|
||||||
|
return LoginResponseToken{}, crypto.MasterKey{}, "", fmt.Errorf("could not get client secret: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
values := urlValues(
|
||||||
|
"client_id", clientID,
|
||||||
|
"client_secret", clientSecret,
|
||||||
|
"scope", loginApiKeyScope,
|
||||||
|
"grant_type", "client_credentials",
|
||||||
|
"deviceType", deviceType(),
|
||||||
|
"deviceName", deviceName,
|
||||||
|
"deviceIdentifier", cfg.ConfigFile.DeviceUUID,
|
||||||
|
)
|
||||||
|
|
||||||
|
var loginResponseToken LoginResponseToken
|
||||||
|
err = authenticatedHTTPPost(ctx, cfg.ConfigFile.IdentityUrl+"/connect/token", &loginResponseToken, values)
|
||||||
|
if err != nil {
|
||||||
|
notify.Notify("Goldwarden", fmt.Sprintf("Could not login via API key: %v", err), "", func() {})
|
||||||
|
return LoginResponseToken{}, crypto.MasterKey{}, "", fmt.Errorf("could not login via API key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
password, err := pinentry.GetPassword("Bitwarden Password", "Enter your Bitwarden password")
|
||||||
|
if err != nil {
|
||||||
|
notify.Notify("Goldwarden", fmt.Sprintf("Could not get password: %v", err), "", func() {})
|
||||||
|
return LoginResponseToken{}, crypto.MasterKey{}, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
masterKey, err := crypto.DeriveMasterKey([]byte(strings.Clone(password)), email, crypto.KDFConfig{Type: crypto.KDFType(loginResponseToken.Kdf), Iterations: uint32(loginResponseToken.KdfIterations), Memory: uint32(loginResponseToken.KdfMemory), Parallelism: uint32(loginResponseToken.KdfParallelism)})
|
||||||
|
if err != nil {
|
||||||
|
notify.Notify("Goldwarden", fmt.Sprintf("Could not derive master key: %v", err), "", func() {})
|
||||||
|
return LoginResponseToken{}, crypto.MasterKey{}, "", err
|
||||||
|
}
|
||||||
|
hashedPassword := b64enc.EncodeToString(pbkdf2.Key(masterKey.GetBytes(), []byte(password), 1, 32, sha256.New))
|
||||||
|
|
||||||
|
authLog.Info("Logged in")
|
||||||
|
return loginResponseToken, masterKey, hashedPassword, nil
|
||||||
|
}
|
||||||
|
|
||||||
func LoginWithMasterpassword(ctx context.Context, email string, cfg *config.Config, vault *vault.Vault) (LoginResponseToken, crypto.MasterKey, string, error) {
|
func LoginWithMasterpassword(ctx context.Context, email string, cfg *config.Config, vault *vault.Vault) (LoginResponseToken, crypto.MasterKey, string, error) {
|
||||||
var preLogin preLoginResponse
|
var preLogin preLoginResponse
|
||||||
if err := authenticatedHTTPPost(ctx, cfg.ConfigFile.ApiUrl+"/accounts/prelogin", &preLogin, preLoginRequest{
|
if err := authenticatedHTTPPost(ctx, cfg.ConfigFile.ApiUrl+"/accounts/prelogin", &preLogin, preLoginRequest{
|
||||||
@ -200,6 +250,50 @@ func RefreshToken(ctx context.Context, cfg *config.Config) bool {
|
|||||||
fmt.Println("Could not get refresh token: ", err)
|
fmt.Println("Could not get refresh token: ", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if token.RefreshToken == "" {
|
||||||
|
authLog.Info("Refreshing using API Key")
|
||||||
|
clientID, err := cfg.GetClientID()
|
||||||
|
if err != nil {
|
||||||
|
authLog.Error("Could not get client ID: %s", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
clientSecret, err := cfg.GetClientSecret()
|
||||||
|
if err != nil {
|
||||||
|
authLog.Error("Could not get client secret: %s", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if clientID != "" && clientSecret != "" {
|
||||||
|
values := urlValues(
|
||||||
|
"client_id", clientID,
|
||||||
|
"client_secret", clientSecret,
|
||||||
|
"scope", loginApiKeyScope,
|
||||||
|
"grant_type", "client_credentials",
|
||||||
|
"deviceType", deviceType(),
|
||||||
|
"deviceName", deviceName,
|
||||||
|
"deviceIdentifier", cfg.ConfigFile.DeviceUUID,
|
||||||
|
)
|
||||||
|
|
||||||
|
var loginResponseToken LoginResponseToken
|
||||||
|
err = authenticatedHTTPPost(ctx, cfg.ConfigFile.IdentityUrl+"/connect/token", &loginResponseToken, values)
|
||||||
|
if err != nil {
|
||||||
|
authLog.Error("Could not refresh token: %s", err.Error())
|
||||||
|
notify.Notify("Goldwarden", fmt.Sprintf("Could not refresh token: %v", err), "", func() {})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.SetToken(config.LoginToken{
|
||||||
|
AccessToken: loginResponseToken.AccessToken,
|
||||||
|
RefreshToken: "",
|
||||||
|
Key: loginResponseToken.Key,
|
||||||
|
TokenType: loginResponseToken.TokenType,
|
||||||
|
ExpiresIn: loginResponseToken.ExpiresIn,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
authLog.Info("No api credentials set")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authLog.Info("Refreshing using refresh token")
|
||||||
|
|
||||||
var loginResponseToken LoginResponseToken
|
var loginResponseToken LoginResponseToken
|
||||||
err = authenticatedHTTPPost(ctx, cfg.ConfigFile.IdentityUrl+"/connect/token", &loginResponseToken, urlValues(
|
err = authenticatedHTTPPost(ctx, cfg.ConfigFile.IdentityUrl+"/connect/token", &loginResponseToken, urlValues(
|
||||||
@ -219,6 +313,7 @@ func RefreshToken(ctx context.Context, cfg *config.Config) bool {
|
|||||||
TokenType: loginResponseToken.TokenType,
|
TokenType: loginResponseToken.TokenType,
|
||||||
ExpiresIn: loginResponseToken.ExpiresIn,
|
ExpiresIn: loginResponseToken.ExpiresIn,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
authLog.Info("Token refreshed")
|
authLog.Info("Token refreshed")
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ type ConfigFile struct {
|
|||||||
IdentityUrl string
|
IdentityUrl string
|
||||||
ApiUrl string
|
ApiUrl string
|
||||||
NotificationsUrl string
|
NotificationsUrl string
|
||||||
|
EncryptedClientID string
|
||||||
|
EncryptedClientSecret string
|
||||||
DeviceUUID string
|
DeviceUUID string
|
||||||
ConfigKeyHash string
|
ConfigKeyHash string
|
||||||
EncryptedToken string
|
EncryptedToken string
|
||||||
@ -88,6 +90,8 @@ func DefaultConfig(useMemguard bool) Config {
|
|||||||
IdentityUrl: "https://vault.bitwarden.com/identity",
|
IdentityUrl: "https://vault.bitwarden.com/identity",
|
||||||
ApiUrl: "https://vault.bitwarden.com/api",
|
ApiUrl: "https://vault.bitwarden.com/api",
|
||||||
NotificationsUrl: "https://notifications.bitwarden.com",
|
NotificationsUrl: "https://notifications.bitwarden.com",
|
||||||
|
EncryptedClientID: "",
|
||||||
|
EncryptedClientSecret: "",
|
||||||
DeviceUUID: deviceUUID.String(),
|
DeviceUUID: deviceUUID.String(),
|
||||||
ConfigKeyHash: "",
|
ConfigKeyHash: "",
|
||||||
EncryptedToken: "",
|
EncryptedToken: "",
|
||||||
@ -241,6 +245,82 @@ func (c *Config) SetToken(token LoginToken) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) GetClientID() (string, error) {
|
||||||
|
if c.IsLocked() {
|
||||||
|
return "", errors.New("config is locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ConfigFile.EncryptedClientID == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := c.decryptString(c.ConfigFile.EncryptedClientID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return decrypted, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) SetClientID(clientID string) error {
|
||||||
|
if c.IsLocked() {
|
||||||
|
return errors.New("config is locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
if clientID == "" {
|
||||||
|
c.ConfigFile.EncryptedClientID = ""
|
||||||
|
c.WriteConfig()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedClientID, err := c.encryptString(clientID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// c.mu.Lock()
|
||||||
|
c.ConfigFile.EncryptedClientID = encryptedClientID
|
||||||
|
// c.mu.Unlock()
|
||||||
|
c.WriteConfig()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) GetClientSecret() (string, error) {
|
||||||
|
if c.IsLocked() {
|
||||||
|
return "", errors.New("config is locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ConfigFile.EncryptedClientSecret == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := c.decryptString(c.ConfigFile.EncryptedClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return decrypted, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) SetClientSecret(clientSecret string) error {
|
||||||
|
if c.IsLocked() {
|
||||||
|
return errors.New("config is locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
if clientSecret == "" {
|
||||||
|
c.ConfigFile.EncryptedClientSecret = ""
|
||||||
|
c.WriteConfig()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedClientSecret, err := c.encryptString(clientSecret)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// c.mu.Lock()
|
||||||
|
c.ConfigFile.EncryptedClientSecret = encryptedClientSecret
|
||||||
|
// c.mu.Unlock()
|
||||||
|
c.WriteConfig()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) GetUserSymmetricKey() ([]byte, error) {
|
func (c *Config) GetUserSymmetricKey() ([]byte, error) {
|
||||||
if c.IsLocked() {
|
if c.IsLocked() {
|
||||||
return []byte{}, errors.New("config is locked")
|
return []byte{}, errors.New("config is locked")
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
FullSyncInterval = 60 * time.Minute
|
FullSyncInterval = 60 * time.Minute
|
||||||
TokenRefreshInterval = 30 * time.Minute
|
TokenRefreshInterval = 10 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logging.GetLogger("Goldwarden", "Agent")
|
var log = logging.GetLogger("Goldwarden", "Agent")
|
||||||
@ -248,6 +248,7 @@ func StartUnixAgent(path string, runtimeConfig config.RuntimeConfig) error {
|
|||||||
for {
|
for {
|
||||||
time.Sleep(FullSyncInterval)
|
time.Sleep(FullSyncInterval)
|
||||||
if !cfg.IsLocked() {
|
if !cfg.IsLocked() {
|
||||||
|
bitwarden.RefreshToken(ctx, &cfg)
|
||||||
token, err := cfg.GetToken()
|
token, err := cfg.GetToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("Could not get token: %s", err.Error())
|
log.Warn("Could not get token: %s", err.Error())
|
||||||
|
@ -106,6 +106,72 @@ var setNotificationsURLCmd = &cobra.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var setApiClientIDCmd = &cobra.Command{
|
||||||
|
Use: "set-api-client-id",
|
||||||
|
Short: "Set the api client id",
|
||||||
|
Long: `Set the api client id.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id := args[0]
|
||||||
|
request := messages.SetClientIDRequest{}
|
||||||
|
request.Value = id
|
||||||
|
|
||||||
|
result, err := commandClient.SendToAgent(request)
|
||||||
|
if err != nil {
|
||||||
|
handleSendToAgentError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch result.(type) {
|
||||||
|
case messages.ActionResponse:
|
||||||
|
if result.(messages.ActionResponse).Success {
|
||||||
|
println("Done")
|
||||||
|
} else {
|
||||||
|
println("Setting api client id failed: " + result.(messages.ActionResponse).Message)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
println("Wrong IPC response type")
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var setApiSecretCmd = &cobra.Command{
|
||||||
|
Use: "set-api-client-secret",
|
||||||
|
Short: "Set the api secret",
|
||||||
|
Long: `Set the api secret.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
secret := args[0]
|
||||||
|
request := messages.SetClientSecretRequest{}
|
||||||
|
request.Value = secret
|
||||||
|
|
||||||
|
result, err := commandClient.SendToAgent(request)
|
||||||
|
if err != nil {
|
||||||
|
handleSendToAgentError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch result.(type) {
|
||||||
|
case messages.ActionResponse:
|
||||||
|
if result.(messages.ActionResponse).Success {
|
||||||
|
println("Done")
|
||||||
|
} else {
|
||||||
|
println("Setting api secret failed: " + result.(messages.ActionResponse).Message)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
println("Wrong IPC response type")
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var getRuntimeConfigCmd = &cobra.Command{
|
var getRuntimeConfigCmd = &cobra.Command{
|
||||||
Use: "get-runtime-config",
|
Use: "get-runtime-config",
|
||||||
Short: "Get the runtime config",
|
Short: "Get the runtime config",
|
||||||
@ -144,4 +210,6 @@ func init() {
|
|||||||
configCmd.AddCommand(setIdentityURLCmd)
|
configCmd.AddCommand(setIdentityURLCmd)
|
||||||
configCmd.AddCommand(setNotificationsURLCmd)
|
configCmd.AddCommand(setNotificationsURLCmd)
|
||||||
configCmd.AddCommand(getRuntimeConfigCmd)
|
configCmd.AddCommand(getRuntimeConfigCmd)
|
||||||
|
configCmd.AddCommand(setApiClientIDCmd)
|
||||||
|
configCmd.AddCommand(setApiSecretCmd)
|
||||||
}
|
}
|
||||||
|
15
go.mod
15
go.mod
@ -9,6 +9,7 @@ require (
|
|||||||
github.com/awnumar/memguard v0.22.4
|
github.com/awnumar/memguard v0.22.4
|
||||||
github.com/google/uuid v1.5.0
|
github.com/google/uuid v1.5.0
|
||||||
github.com/gorilla/websocket v1.5.1
|
github.com/gorilla/websocket v1.5.1
|
||||||
|
github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5
|
||||||
github.com/lox/go-touchid v0.0.0-20170712105233-619cc8e578d0
|
github.com/lox/go-touchid v0.0.0-20170712105233-619cc8e578d0
|
||||||
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a
|
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a
|
||||||
github.com/mitchellh/go-ps v1.0.0
|
github.com/mitchellh/go-ps v1.0.0
|
||||||
@ -23,22 +24,8 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
|
||||||
github.com/go-text/typesetting v0.0.0-20230602202114-9797aefac433 // indirect
|
|
||||||
github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5 // indirect
|
|
||||||
github.com/k0kubun/pp v2.4.0+incompatible // indirect
|
|
||||||
github.com/k0kubun/pp/v3 v3.2.0 // indirect
|
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
|
||||||
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
|
||||||
github.com/tklauser/numcpus v0.7.0 // indirect
|
|
||||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
|
||||||
golang.org/x/exp/shiny v0.0.0-20231219180239-dc181d75b848 // indirect
|
|
||||||
golang.org/x/image v0.14.0 // indirect
|
|
||||||
golang.org/x/net v0.19.0 // indirect
|
golang.org/x/net v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.15.0 // indirect
|
golang.org/x/sys v0.15.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
22
go.sum
22
go.sum
@ -1,11 +1,3 @@
|
|||||||
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY=
|
|
||||||
gioui.org v0.1.0 h1:fEDY5A4+epOdzjCBYSUC4BzvjWqsjfqf5D6mskbthOs=
|
|
||||||
gioui.org v0.1.0/go.mod h1:a3hz8FyrPMkt899D9YrxMGtyRzpPrJpz1Lzbssn81vI=
|
|
||||||
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
|
||||||
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc=
|
|
||||||
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
|
||||||
gioui.org/shader v1.0.6 h1:cvZmU+eODFR2545X+/8XucgZdTtEjR3QWW6W65b0q5Y=
|
|
||||||
gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
|
|
||||||
github.com/LlamaNite/llamalog v0.2.1 h1:k9XugHmyQqJhCrogca808Jl2rrEKIWMtWyLKX+xX9Mg=
|
github.com/LlamaNite/llamalog v0.2.1 h1:k9XugHmyQqJhCrogca808Jl2rrEKIWMtWyLKX+xX9Mg=
|
||||||
github.com/LlamaNite/llamalog v0.2.1/go.mod h1:zopgmWk8utZPfZCPa/uvQkv99Lan3pRrw/9inbIYZeo=
|
github.com/LlamaNite/llamalog v0.2.1/go.mod h1:zopgmWk8utZPfZCPa/uvQkv99Lan3pRrw/9inbIYZeo=
|
||||||
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
|
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
|
||||||
@ -22,11 +14,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8
|
|||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/go-text/typesetting v0.0.0-20230602202114-9797aefac433 h1:Pdyvqsfi1QYgFfZa4R8otBOtgO+CGyBDMEG8cM3jwvE=
|
|
||||||
github.com/go-text/typesetting v0.0.0-20230602202114-9797aefac433/go.mod h1:KmrpWuSMFcO2yjmyhGpnBGQHSKAoEgMTSSzvLDzCuEA=
|
|
||||||
github.com/go-text/typesetting-utils v0.0.0-20230412163830-89e4bcfa3ecc h1:9Kf84pnrmmjdRzZIkomfjowmGUhHs20jkrWYw/I6CYc=
|
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
@ -71,8 +60,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
|||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
|
||||||
github.com/tink-crypto/tink-go/v2 v2.1.0 h1:QXFBguwMwTIaU17EgZpEJWsUSc60b1BAGTzBIoMdmok=
|
github.com/tink-crypto/tink-go/v2 v2.1.0 h1:QXFBguwMwTIaU17EgZpEJWsUSc60b1BAGTzBIoMdmok=
|
||||||
github.com/tink-crypto/tink-go/v2 v2.1.0/go.mod h1:y1TnYFt1i2eZVfx4OGc+C+EMp4CoKWAw2VSEuoicHHI=
|
github.com/tink-crypto/tink-go/v2 v2.1.0/go.mod h1:y1TnYFt1i2eZVfx4OGc+C+EMp4CoKWAw2VSEuoicHHI=
|
||||||
github.com/twpayne/go-pinentry v0.3.0 h1:Rr+fEOZXmeItOb4thjeVaBWJKB9Xa/eojolycyF/26c=
|
github.com/twpayne/go-pinentry v0.3.0 h1:Rr+fEOZXmeItOb4thjeVaBWJKB9Xa/eojolycyF/26c=
|
||||||
@ -85,10 +73,6 @@ golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
|||||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE=
|
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE=
|
||||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||||
golang.org/x/exp/shiny v0.0.0-20231219180239-dc181d75b848 h1:LnDWUUS+bxOesHc+QBvFFmS4v0ZH+Vtg0EncMANwN9Q=
|
|
||||||
golang.org/x/exp/shiny v0.0.0-20231219180239-dc181d75b848/go.mod h1:UH99kUObWAZkDnWqppdQe5ZhPYESUw8I0zVV1uWBR+0=
|
|
||||||
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
|
|
||||||
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
|
||||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -100,8 +84,6 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
@ -14,6 +14,14 @@ type SetNotificationsURLRequest struct {
|
|||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SetClientIDRequest struct {
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetClientSecretRequest struct {
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
type GetRuntimeConfigRequest struct{}
|
type GetRuntimeConfigRequest struct{}
|
||||||
|
|
||||||
type GetRuntimeConfigResponse struct {
|
type GetRuntimeConfigResponse struct {
|
||||||
@ -67,4 +75,22 @@ func init() {
|
|||||||
}
|
}
|
||||||
return req, nil
|
return req, nil
|
||||||
}, GetRuntimeConfigResponse{})
|
}, GetRuntimeConfigResponse{})
|
||||||
|
|
||||||
|
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||||
|
var req SetClientIDRequest
|
||||||
|
err := json.Unmarshal(payload, &req)
|
||||||
|
if err != nil {
|
||||||
|
panic("Unmarshal: " + err.Error())
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}, SetClientIDRequest{})
|
||||||
|
|
||||||
|
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||||
|
var req SetClientSecretRequest
|
||||||
|
err := json.Unmarshal(payload, &req)
|
||||||
|
if err != nil {
|
||||||
|
panic("Unmarshal: " + err.Error())
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}, SetClientSecretRequest{})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user