mirror of
https://github.com/quexten/goldwarden.git
synced 2024-08-16 22:50:27 +03:00
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()
|
||||
if err == nil {
|
||||
if token.AccessToken != "" {
|
||||
bitwarden.RefreshToken(ctx, cfg)
|
||||
refreshed := bitwarden.RefreshToken(ctx, cfg)
|
||||
if !refreshed {
|
||||
return false
|
||||
}
|
||||
|
||||
userSymmetricKey, err := cfg.GetUserSymmetricKey()
|
||||
if err != nil {
|
||||
return false
|
||||
@ -83,10 +87,17 @@ func ensureIsNotLocked(action Action) Action {
|
||||
ctx1 := context.Background()
|
||||
success := sync(ctx1, vault, cfg)
|
||||
if err != nil || !success {
|
||||
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
if err != nil {
|
||||
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
} else {
|
||||
return messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: "Could not sync vault",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return messages.IPCMessageFromPayload(messages.GetRuntimeConfigResponse{
|
||||
UseMemguard: cfg.ConfigFile.RuntimeConfig.UseMemguard,
|
||||
@ -68,4 +100,6 @@ func init() {
|
||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetApiURLRequest{}), handleSetApiURL)
|
||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.SetNotificationsURLRequest{}), handleSetNotifications)
|
||||
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 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)
|
||||
} else {
|
||||
token, masterKey, masterpasswordHash, err = bitwarden.LoginWithMasterpassword(ctx, req.Email, cfg, vault)
|
||||
|
@ -38,11 +38,15 @@ type preLoginResponse struct {
|
||||
}
|
||||
|
||||
type LoginResponseToken struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
TokenType string `json:"token_type"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
Key string `json:"key"`
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
TokenType string `json:"token_type"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
Key string `json:"key"`
|
||||
Kdf int `json:"Kdf"`
|
||||
KdfIterations int `json:"KdfIterations"`
|
||||
KdfMemory int `json:"KdfMemory"`
|
||||
KdfParallelism int `json:"KdfParallelism"`
|
||||
}
|
||||
|
||||
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) {
|
||||
var preLogin preLoginResponse
|
||||
if err := authenticatedHTTPPost(ctx, cfg.ConfigFile.ApiUrl+"/accounts/prelogin", &preLogin, preLoginRequest{
|
||||
@ -200,25 +250,70 @@ func RefreshToken(ctx context.Context, cfg *config.Config) bool {
|
||||
fmt.Println("Could not get refresh token: ", err)
|
||||
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
|
||||
}
|
||||
|
||||
var loginResponseToken LoginResponseToken
|
||||
err = authenticatedHTTPPost(ctx, cfg.ConfigFile.IdentityUrl+"/connect/token", &loginResponseToken, urlValues(
|
||||
"grant_type", "refresh_token",
|
||||
"refresh_token", token.RefreshToken,
|
||||
"client_id", "connector",
|
||||
))
|
||||
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
|
||||
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
|
||||
err = authenticatedHTTPPost(ctx, cfg.ConfigFile.IdentityUrl+"/connect/token", &loginResponseToken, urlValues(
|
||||
"grant_type", "refresh_token",
|
||||
"refresh_token", token.RefreshToken,
|
||||
"client_id", "connector",
|
||||
))
|
||||
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: loginResponseToken.RefreshToken,
|
||||
Key: loginResponseToken.Key,
|
||||
TokenType: loginResponseToken.TokenType,
|
||||
ExpiresIn: loginResponseToken.ExpiresIn,
|
||||
})
|
||||
}
|
||||
cfg.SetToken(config.LoginToken{
|
||||
AccessToken: loginResponseToken.AccessToken,
|
||||
RefreshToken: loginResponseToken.RefreshToken,
|
||||
Key: loginResponseToken.Key,
|
||||
TokenType: loginResponseToken.TokenType,
|
||||
ExpiresIn: loginResponseToken.ExpiresIn,
|
||||
})
|
||||
|
||||
authLog.Info("Token refreshed")
|
||||
|
||||
|
@ -54,6 +54,8 @@ type ConfigFile struct {
|
||||
IdentityUrl string
|
||||
ApiUrl string
|
||||
NotificationsUrl string
|
||||
EncryptedClientID string
|
||||
EncryptedClientSecret string
|
||||
DeviceUUID string
|
||||
ConfigKeyHash string
|
||||
EncryptedToken string
|
||||
@ -88,6 +90,8 @@ func DefaultConfig(useMemguard bool) Config {
|
||||
IdentityUrl: "https://vault.bitwarden.com/identity",
|
||||
ApiUrl: "https://vault.bitwarden.com/api",
|
||||
NotificationsUrl: "https://notifications.bitwarden.com",
|
||||
EncryptedClientID: "",
|
||||
EncryptedClientSecret: "",
|
||||
DeviceUUID: deviceUUID.String(),
|
||||
ConfigKeyHash: "",
|
||||
EncryptedToken: "",
|
||||
@ -241,6 +245,82 @@ func (c *Config) SetToken(token LoginToken) error {
|
||||
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) {
|
||||
if c.IsLocked() {
|
||||
return []byte{}, errors.New("config is locked")
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
|
||||
const (
|
||||
FullSyncInterval = 60 * time.Minute
|
||||
TokenRefreshInterval = 30 * time.Minute
|
||||
TokenRefreshInterval = 10 * time.Minute
|
||||
)
|
||||
|
||||
var log = logging.GetLogger("Goldwarden", "Agent")
|
||||
@ -248,6 +248,7 @@ func StartUnixAgent(path string, runtimeConfig config.RuntimeConfig) error {
|
||||
for {
|
||||
time.Sleep(FullSyncInterval)
|
||||
if !cfg.IsLocked() {
|
||||
bitwarden.RefreshToken(ctx, &cfg)
|
||||
token, err := cfg.GetToken()
|
||||
if err != nil {
|
||||
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{
|
||||
Use: "get-runtime-config",
|
||||
Short: "Get the runtime config",
|
||||
@ -144,4 +210,6 @@ func init() {
|
||||
configCmd.AddCommand(setIdentityURLCmd)
|
||||
configCmd.AddCommand(setNotificationsURLCmd)
|
||||
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/google/uuid v1.5.0
|
||||
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/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a
|
||||
github.com/mitchellh/go-ps v1.0.0
|
||||
@ -23,22 +24,8 @@ require (
|
||||
|
||||
require (
|
||||
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/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
)
|
||||
|
||||
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/go.mod h1:zopgmWk8utZPfZCPa/uvQkv99Lan3pRrw/9inbIYZeo=
|
||||
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/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/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.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.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
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/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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
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/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/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/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/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
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/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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=
|
||||
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=
|
||||
|
@ -14,6 +14,14 @@ type SetNotificationsURLRequest struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
type SetClientIDRequest struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
type SetClientSecretRequest struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
type GetRuntimeConfigRequest struct{}
|
||||
|
||||
type GetRuntimeConfigResponse struct {
|
||||
@ -67,4 +75,22 @@ func init() {
|
||||
}
|
||||
return req, nil
|
||||
}, 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…
Reference in New Issue
Block a user