Compare commits
77 Commits
fix/wrong_
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
829193e70c | ||
|
dd063cc768 | ||
|
eae9246310 | ||
|
6cbebdf6c7 | ||
|
490dfae155 | ||
|
d3bc35deb2 | ||
|
cffa650124 | ||
|
51940fa770 | ||
|
b62ffb2cb4 | ||
|
ff1ae8316e | ||
|
49ee2cbe29 | ||
|
4b0b90699f | ||
|
1317e1e037 | ||
|
b15c883559 | ||
|
2bce296d6a | ||
|
8175406617 | ||
|
f05ab33670 | ||
|
16b86527ad | ||
|
c5d57c95e1 | ||
|
6c17984bd0 | ||
|
9daaf53d39 | ||
|
59be4814a1 | ||
|
0dd6ac1188 | ||
|
140026386e | ||
|
aab01aaf6c | ||
|
ad1ab73d71 | ||
|
927b08d441 | ||
|
5806475998 | ||
|
f38fd2edec | ||
|
71b145ad41 | ||
|
2f93774405 | ||
|
c86e32de7e | ||
|
a938090de7 | ||
|
3c3c54906a | ||
|
bc133ee2c6 | ||
|
5d1192113a | ||
|
fa4b735635 | ||
|
4a2d3a9e92 | ||
|
553f88a66e | ||
|
55c6aa2b8c | ||
|
7ea364b1c3 | ||
|
977f21c4a9 | ||
|
f80982a24f | ||
|
b1e632588f | ||
|
2bf75430f3 | ||
|
f7e1cae015 | ||
|
1c9bf6101b | ||
|
9a0ffded83 | ||
|
97a485712e | ||
|
79bfc43ab8 | ||
|
d32147bdf8 | ||
|
53271c3331 | ||
|
5af6771460 | ||
|
9ae9401542 | ||
|
833b0225f1 | ||
|
bcecb10e22 | ||
|
dc32d85fcb | ||
|
6323babce0 | ||
|
670efc076f | ||
|
2651a36d3c | ||
|
a41c91ca6b | ||
|
275ba9a3d2 | ||
|
0146533075 | ||
|
d85cea14ff | ||
|
09c7e7521f | ||
|
aed218429a | ||
|
b9b10fd6e8 | ||
|
e9471caede | ||
|
259d8eb437 | ||
|
742ceddf15 | ||
|
26d12fd5ce | ||
|
50451914f2 | ||
|
b8b0dd9bf9 | ||
|
08f419ac36 | ||
|
e913180798 | ||
|
d70dd90630 | ||
|
9fbf1a08ee |
2
.github/com.quexten.Goldwarden.yml
vendored
2
.github/com.quexten.Goldwarden.yml
vendored
@ -40,7 +40,7 @@ modules:
|
||||
- cp -R ./* /app/bin
|
||||
- chmod +x /app/bin/goldwarden_ui_main.py
|
||||
- install -D ./com.quexten.Goldwarden.desktop /app/share/applications/com.quexten.Goldwarden.desktop
|
||||
- install -D ./goldwarden.svg /app/share/icons/hicolor/scalable/apps/com.quexten.Goldwarden.svg
|
||||
- install -D ./com.quexten.Goldwarden.svg /app/share/icons/hicolor/scalable/apps/com.quexten.Goldwarden.svg
|
||||
- install -Dm644 ./com.quexten.Goldwarden.metainfo.xml -t /app/share/metainfo/
|
||||
- blueprint-compiler batch-compile /app/bin/src/gui/.templates/ /app/bin/src/gui/ /app/bin/src/gui/*.blp
|
||||
sources:
|
||||
|
4
.github/workflows/flatpak.yml
vendored
4
.github/workflows/flatpak.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
run: sudo apt-get install -y libfido2-dev
|
||||
- name: Build
|
||||
run: go build -o goldwarden -v .
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: goldwarden
|
||||
path: ./goldwarden
|
||||
@ -37,7 +37,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download daemon
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: goldwarden
|
||||
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -114,7 +114,7 @@ jobs:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build_macos_x86_64:
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-13
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
@ -1,4 +1,4 @@
|
||||
<img src="https://raw.githubusercontent.com/quexten/goldwarden/main/gui/goldwarden.svg" width=200>
|
||||
<img src="https://raw.githubusercontent.com/quexten/goldwarden/main/gui/com.quexten.Goldwarden.svg" width=200>
|
||||
|
||||
# Goldwarden
|
||||
|
||||
|
@ -16,12 +16,24 @@ import (
|
||||
func handleAddSSH(msg messages.IPCMessage, cfg *config.Config, vault *vault.Vault, callingContext *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
||||
req := messages.ParsePayload(msg).(messages.CreateSSHKeyRequest)
|
||||
|
||||
cipher, publicKey := ssh.NewSSHKeyCipher(req.Name, vault.Keyring)
|
||||
cipher, publicKey, err := ssh.NewSSHKeyCipher(req.Name, vault.Keyring)
|
||||
if err != nil {
|
||||
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: true,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := cfg.GetToken()
|
||||
@ -56,7 +68,49 @@ func handleListSSH(msg messages.IPCMessage, cfg *config.Config, vault *vault.Vau
|
||||
return
|
||||
}
|
||||
|
||||
func handleImportSSH(msg messages.IPCMessage, cfg *config.Config, vault *vault.Vault, callingContext *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
||||
req := messages.ParsePayload(msg).(messages.ImportSSHKeyRequest)
|
||||
|
||||
cipher, _, err := ssh.SSHKeyCipherFromKey(req.Name, req.Key, vault.Keyring)
|
||||
if err != nil {
|
||||
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: true,
|
||||
})
|
||||
if err != nil {
|
||||
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||
Success: false,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := cfg.GetToken()
|
||||
if err != nil {
|
||||
actionsLog.Warn(err.Error())
|
||||
}
|
||||
ctx := context.WithValue(context.TODO(), bitwarden.AuthToken{}, token.AccessToken)
|
||||
postedCipher, err := bitwarden.PostCipher(ctx, cipher, cfg)
|
||||
if err == nil {
|
||||
vault.AddOrUpdateSecureNote(postedCipher)
|
||||
} else {
|
||||
actionsLog.Warn("Error posting ssh key cipher: " + err.Error())
|
||||
}
|
||||
|
||||
response, err = messages.IPCMessageFromPayload(messages.ImportSSHKeyResponse{
|
||||
Success: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func init() {
|
||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.CreateSSHKeyRequest{}), ensureEverything(systemauth.SSHKey, handleAddSSH))
|
||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.GetSSHKeysRequest{}), ensureIsNotLocked(ensureIsLoggedIn(handleListSSH)))
|
||||
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.ImportSSHKeyRequest{}), ensureEverything(systemauth.SSHKey, handleImportSSH))
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ func handleVaultStatus(request messages.IPCMessage, cfg *config.Config, vault *v
|
||||
vaultStatus.NumberOfLogins = len(vault.GetLogins())
|
||||
vaultStatus.NumberOfNotes = len(vault.GetNotes())
|
||||
vaultStatus.LastSynced = vault.GetLastSynced()
|
||||
vaultStatus.WebsockedConnected = vault.IsWebsocketConnected()
|
||||
vaultStatus.WebsocketConnected = vault.IsWebsocketConnected()
|
||||
vaultStatus.PinSet = cfg.HasPin()
|
||||
vaultStatus.LoggedIn = cfg.IsLoggedIn()
|
||||
response, err = messages.IPCMessageFromPayload(vaultStatus)
|
||||
|
@ -116,7 +116,8 @@ func LoginWithApiKey(ctx context.Context, email string, cfg *config.Config, vaul
|
||||
|
||||
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{
|
||||
fmt.Println("Posting prelogin")
|
||||
if err := authenticatedHTTPPost(ctx, cfg.ConfigFile.IdentityUrl+"/accounts/prelogin", &preLogin, preLoginRequest{
|
||||
Email: email,
|
||||
}); err != nil {
|
||||
notify.Notify("Goldwarden", fmt.Sprintf("Could not pre-login: %v", err), "", 0, func() {})
|
||||
@ -127,12 +128,14 @@ func LoginWithMasterpassword(ctx context.Context, email string, cfg *config.Conf
|
||||
var masterKey crypto.MasterKey
|
||||
var hashedPassword string
|
||||
|
||||
fmt.Println("Getting password")
|
||||
password, err := pinentry.GetPassword("Bitwarden Password", "Enter your Bitwarden password")
|
||||
if err != nil {
|
||||
notify.Notify("Goldwarden", fmt.Sprintf("Could not get password: %v", err), "", 0, func() {})
|
||||
return LoginResponseToken{}, crypto.MasterKey{}, "", err
|
||||
}
|
||||
|
||||
fmt.Println("Deriving master key")
|
||||
masterKey, err = crypto.DeriveMasterKey([]byte(strings.Clone(password)), email, crypto.KDFConfig{Type: crypto.KDFType(preLogin.KDF), Iterations: uint32(preLogin.KDFIterations), Memory: uint32(preLogin.KDFMemory), Parallelism: uint32(preLogin.KDFParallelism)})
|
||||
if err != nil {
|
||||
notify.Notify("Goldwarden", fmt.Sprintf("Could not derive master key: %v", err), "", 0, func() {})
|
||||
@ -142,14 +145,14 @@ func LoginWithMasterpassword(ctx context.Context, email string, cfg *config.Conf
|
||||
hashedPassword = b64enc.EncodeToString(pbkdf2.Key(masterKey.GetBytes(), []byte(password), 1, 32, sha256.New))
|
||||
|
||||
values = urlValues(
|
||||
"scope", loginScope,
|
||||
"client_id", "web",
|
||||
"deviceType", "10",
|
||||
"deviceIdentifier", cfg.ConfigFile.DeviceUUID,
|
||||
"deviceName", "firefox",
|
||||
"grant_type", "password",
|
||||
"username", email,
|
||||
"password", string(hashedPassword),
|
||||
"scope", loginScope,
|
||||
"client_id", "connector",
|
||||
"deviceType", deviceType(),
|
||||
"deviceName", deviceName,
|
||||
"deviceIdentifier", cfg.ConfigFile.DeviceUUID,
|
||||
)
|
||||
|
||||
var loginResponseToken LoginResponseToken
|
||||
|
@ -51,7 +51,7 @@ func authenticatedHTTPPost(ctx context.Context, urlstr string, recv, send interf
|
||||
}
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
if authEmail != "" {
|
||||
req.Header.Set("Auth-Email", base64.URLEncoding.EncodeToString([]byte(authEmail)))
|
||||
req.Header.Set("Auth-Email", base64.RawURLEncoding.EncodeToString([]byte(authEmail)))
|
||||
}
|
||||
return makeAuthenticatedHTTPRequest(ctx, req, recv)
|
||||
}
|
||||
@ -97,7 +97,12 @@ func makeAuthenticatedHTTPRequest(ctx context.Context, req *http.Request, recv i
|
||||
if token, ok := ctx.Value(AuthToken{}).(string); ok {
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
req.Header.Set("device-type", deviceType())
|
||||
req.Header.Set("Accept", "*/*")
|
||||
req.Header.Set("Accept-Language", "en-US,en;q=0.5")
|
||||
req.Header.Set("User-Agent", "Goldwarden (github.com/quexten/goldwarden)")
|
||||
req.Header.Set("Device-Type", "10")
|
||||
req.Header.Set("Bitwarden-Client-Name", "goldwarden")
|
||||
req.Header.Set("Bitwarden-Client-Version", "0.0.0")
|
||||
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
|
@ -8,74 +8,77 @@ import (
|
||||
)
|
||||
|
||||
type SyncData struct {
|
||||
Profile Profile
|
||||
Folders []Folder
|
||||
Ciphers []Cipher
|
||||
Profile Profile `json:"profile"`
|
||||
Folders []Folder `json:"folders"`
|
||||
Ciphers []Cipher `json:"ciphers"`
|
||||
}
|
||||
|
||||
type Organization struct {
|
||||
Object string
|
||||
Id uuid.UUID
|
||||
Name string
|
||||
UseGroups bool
|
||||
UseDirectory bool
|
||||
UseEvents bool
|
||||
UseTotp bool
|
||||
Use2fa bool
|
||||
UseApi bool
|
||||
UsersGetPremium bool
|
||||
SelfHost bool
|
||||
Seats int
|
||||
MaxCollections int
|
||||
MaxStorageGb int
|
||||
Key string
|
||||
Status int
|
||||
Type int
|
||||
Enabled bool
|
||||
Object string `json:"object"`
|
||||
Id uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
UseGroups bool `json:"useGroups"`
|
||||
UseDirectory bool `json:"useDirectory"`
|
||||
UseEvents bool `json:"useEvents"`
|
||||
UseTotp bool `json:"useTotp"`
|
||||
Use2fa bool `json:"use2fa"`
|
||||
UseApi bool `json:"useApi"`
|
||||
UsersGetPremium bool `json:"usersGetPremium"`
|
||||
SelfHost bool `json:"selfHost"`
|
||||
Seats int `json:"seats"`
|
||||
MaxCollections int `json:"maxCollections"`
|
||||
MaxStorageGb int `json:"maxStorageGb"`
|
||||
Key string `json:"key"`
|
||||
Status int `json:"status"`
|
||||
Type int `json:"type"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type Profile struct {
|
||||
ID uuid.UUID
|
||||
Name string
|
||||
Email string
|
||||
EmailVerified bool
|
||||
Premium bool
|
||||
MasterPasswordHint string
|
||||
Culture string
|
||||
TwoFactorEnabled bool
|
||||
Key crypto.EncString
|
||||
PrivateKey crypto.EncString
|
||||
SecurityStamp string
|
||||
Organizations []Organization
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"emailVerified"`
|
||||
Premium bool `json:"premium"`
|
||||
MasterPasswordHint string `json:"masterPasswordHint"`
|
||||
Culture string `json:"culture"`
|
||||
TwoFactorEnabled bool `json:"twoFactorEnabled"`
|
||||
Key crypto.EncString `json:"key"`
|
||||
PrivateKey crypto.EncString `json:"privateKey"`
|
||||
SecurityStamp string `json:"securityStamp"`
|
||||
Organizations []Organization `json:"organizations"`
|
||||
}
|
||||
|
||||
type Folder struct {
|
||||
ID uuid.UUID
|
||||
Name string
|
||||
RevisionDate time.Time
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
RevisionDate time.Time `json:"revisionDate"`
|
||||
}
|
||||
|
||||
type Cipher struct {
|
||||
Type CipherType
|
||||
ID *uuid.UUID `json:",omitempty"`
|
||||
Name crypto.EncString
|
||||
Edit bool
|
||||
RevisionDate time.Time
|
||||
DeletedDate time.Time
|
||||
Type CipherType `json:"type,omitempty"`
|
||||
ID *uuid.UUID `json:"id,omitempty"`
|
||||
Name crypto.EncString `json:"name,omitempty"`
|
||||
Edit bool `json:"edit,omitempty"`
|
||||
RevisionDate time.Time `json:"revisionDate,omitempty"`
|
||||
DeletedDate time.Time `json:"deletedDate,omitempty"`
|
||||
|
||||
FolderID *uuid.UUID `json:",omitempty"`
|
||||
OrganizationID *uuid.UUID `json:",omitempty"`
|
||||
Favorite bool `json:",omitempty"`
|
||||
Attachments interface{} `json:",omitempty"`
|
||||
OrganizationUseTotp bool `json:",omitempty"`
|
||||
CollectionIDs []string `json:",omitempty"`
|
||||
Fields []Field `json:",omitempty"`
|
||||
FolderID *uuid.UUID `json:"folderId,omitempty"`
|
||||
OrganizationID *uuid.UUID `json:"organizationId,omitempty"`
|
||||
Favorite bool `json:"favorite,omitempty"`
|
||||
Attachments interface{} `json:"attachments,omitempty"`
|
||||
OrganizationUseTotp bool `json:"organizationUseTotp,omitempty"`
|
||||
CollectionIDs []string `json:"collectionIds,omitempty"`
|
||||
Fields []Field `json:"fields,omitempty"`
|
||||
|
||||
Card *Card `json:",omitempty"`
|
||||
Identity *Identity `json:",omitempty"`
|
||||
Login *LoginCipher `json:",omitempty"`
|
||||
Notes *crypto.EncString `json:",omitempty"`
|
||||
SecureNote *SecureNoteCipher `json:",omitempty"`
|
||||
Card *Card `json:"card,omitempty"`
|
||||
Identity *Identity `json:"identity,omitempty"`
|
||||
Login *LoginCipher `json:"login,omitempty"`
|
||||
Notes *crypto.EncString `json:"notes,omitempty"`
|
||||
SecureNote *SecureNoteCipher `json:"secureNote,omitempty"`
|
||||
SSHKey *SSHKeyCipher `json:"sshKey,omitempty"`
|
||||
|
||||
Key *crypto.EncString `json:"key,omitempty"`
|
||||
}
|
||||
|
||||
type CipherType int
|
||||
@ -86,59 +89,66 @@ const (
|
||||
CipherCard = 3
|
||||
CipherIdentity = 4
|
||||
CipherNote = 2
|
||||
CipherSSHKey = 5
|
||||
)
|
||||
|
||||
type SSHKeyCipher struct {
|
||||
PrivateKey crypto.EncString `json:"privateKey"`
|
||||
PublicKey crypto.EncString `json:"publicKey"`
|
||||
KeyFingerprint crypto.EncString `json:"keyFingerprint"`
|
||||
}
|
||||
|
||||
type Card struct {
|
||||
CardholderName crypto.EncString
|
||||
Brand crypto.EncString
|
||||
Number crypto.EncString
|
||||
ExpMonth crypto.EncString
|
||||
ExpYear crypto.EncString
|
||||
Code crypto.EncString
|
||||
CardholderName crypto.EncString `json:"cardholderName"`
|
||||
Brand crypto.EncString `json:"brand"`
|
||||
Number crypto.EncString `json:"number"`
|
||||
ExpMonth crypto.EncString `json:"expMonth"`
|
||||
ExpYear crypto.EncString `json:"expYear"`
|
||||
Code crypto.EncString `json:"code"`
|
||||
}
|
||||
|
||||
type Identity struct {
|
||||
Title crypto.EncString
|
||||
FirstName crypto.EncString
|
||||
MiddleName crypto.EncString
|
||||
LastName crypto.EncString
|
||||
Title crypto.EncString `json:"title"`
|
||||
FirstName crypto.EncString `json:"firstName"`
|
||||
MiddleName crypto.EncString `json:"middleName"`
|
||||
LastName crypto.EncString `json:"lastName"`
|
||||
|
||||
Username crypto.EncString
|
||||
Company crypto.EncString
|
||||
SSN crypto.EncString
|
||||
PassportNumber crypto.EncString
|
||||
LicenseNumber crypto.EncString
|
||||
Username crypto.EncString `json:"username"`
|
||||
Company crypto.EncString `json:"company"`
|
||||
SSN crypto.EncString `json:"ssn"`
|
||||
PassportNumber crypto.EncString `json:"passportNumber"`
|
||||
LicenseNumber crypto.EncString `json:"licenseNumber"`
|
||||
|
||||
Email crypto.EncString
|
||||
Phone crypto.EncString
|
||||
Address1 crypto.EncString
|
||||
Address2 crypto.EncString
|
||||
Address3 crypto.EncString
|
||||
City crypto.EncString
|
||||
State crypto.EncString
|
||||
PostalCode crypto.EncString
|
||||
Country crypto.EncString
|
||||
Email crypto.EncString `json:"email"`
|
||||
Phone crypto.EncString `json:"phone"`
|
||||
Address1 crypto.EncString `json:"address1"`
|
||||
Address2 crypto.EncString `json:"address2"`
|
||||
Address3 crypto.EncString `json:"address3"`
|
||||
City crypto.EncString `json:"city"`
|
||||
State crypto.EncString `json:"state"`
|
||||
PostalCode crypto.EncString `json:"postalCode"`
|
||||
Country crypto.EncString `json:"country"`
|
||||
}
|
||||
|
||||
type FieldType int
|
||||
type Field struct {
|
||||
Type FieldType
|
||||
Name crypto.EncString
|
||||
Value crypto.EncString
|
||||
Type FieldType `json:"type,omitempty"`
|
||||
Name crypto.EncString `json:"name,omitempty"`
|
||||
Value crypto.EncString `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
type LoginCipher struct {
|
||||
Password crypto.EncString
|
||||
URI crypto.EncString
|
||||
URIs []URI
|
||||
Username crypto.EncString `json:",omitempty"`
|
||||
Totp crypto.EncString `json:",omitempty"`
|
||||
Password crypto.EncString `json:"password,omitempty"`
|
||||
URI crypto.EncString `json:"uri,omitempty"`
|
||||
URIs []URI `json:"uris,omitempty"`
|
||||
Username crypto.EncString `json:"username,omitempty"`
|
||||
Totp crypto.EncString `json:"totp,omitempty"`
|
||||
}
|
||||
|
||||
type URIMatch int
|
||||
type URI struct {
|
||||
URI string
|
||||
Match URIMatch
|
||||
URI string `json:"uri,omitempty"`
|
||||
Match URIMatch `json:"match,omitempty"`
|
||||
}
|
||||
|
||||
type SecureNoteType int
|
||||
@ -147,8 +157,26 @@ type SecureNoteCipher struct {
|
||||
}
|
||||
|
||||
func (cipher Cipher) GetKeyForCipher(keyring crypto.Keyring) (crypto.SymmetricEncryptionKey, error) {
|
||||
var key1 crypto.SymmetricEncryptionKey = nil
|
||||
var err error
|
||||
if cipher.OrganizationID != nil {
|
||||
return keyring.GetSymmetricKeyForOrganization(cipher.OrganizationID.String())
|
||||
key1, err = keyring.GetSymmetricKeyForOrganization(cipher.OrganizationID.String())
|
||||
} else {
|
||||
key1, err = keyring.GetAccountKey(), nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cipher.Key == nil {
|
||||
return key1, nil
|
||||
} else {
|
||||
key, err := crypto.DecryptWith(*cipher.Key, key1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return crypto.MemorySymmetricEncryptionKeyFromBytes(key)
|
||||
}
|
||||
}
|
||||
return keyring.GetAccountKey(), nil
|
||||
}
|
||||
|
@ -59,6 +59,8 @@ func DoFullSync(ctx context.Context, vault *vault.Vault, config *config.Config,
|
||||
vault.AddOrUpdateLogin(cipher)
|
||||
case models.CipherNote:
|
||||
vault.AddOrUpdateSecureNote(cipher)
|
||||
case models.CipherSSHKey:
|
||||
vault.AddOrUpdateSSHKey(cipher)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,12 +255,11 @@ func parseMessageTypeFromMessagePack(messagePack []byte) (int8, string, bool) {
|
||||
return 0, "", false
|
||||
}
|
||||
if len(value) < 5 {
|
||||
websocketLog.Warn("Invalid message received, length too short")
|
||||
return 0, "", false
|
||||
}
|
||||
value, success := value[4].([]interface{})
|
||||
if len(value) < 1 || !success {
|
||||
websocketLog.Warn("Invalid message received, length too short")
|
||||
websocketLog.Warn("Invalid message received, value length less than 1")
|
||||
return 0, "", false
|
||||
}
|
||||
value1, success := value[0].(map[string]interface{})
|
||||
|
@ -89,8 +89,8 @@ func DefaultConfig(useMemguard bool) Config {
|
||||
useMemguard,
|
||||
&keyBuffer,
|
||||
ConfigFile{
|
||||
IdentityUrl: "https://vault.bitwarden.com/identity",
|
||||
ApiUrl: "https://vault.bitwarden.com/api",
|
||||
IdentityUrl: "https://identity.bitwarden.com",
|
||||
ApiUrl: "https://api.bitwarden.com",
|
||||
NotificationsUrl: "https://notifications.bitwarden.com",
|
||||
VaultUrl: "https://vault.bitwarden.com",
|
||||
EncryptedClientID: "",
|
||||
|
@ -12,8 +12,55 @@ import (
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func NewSSHKeyCipher(name string, keyring *crypto.Keyring) (models.Cipher, string) {
|
||||
// todo refactor to share code
|
||||
func SSHKeyCipherFromKey(name string, privateKey string, keyring *crypto.Keyring) (models.Cipher, string, error) {
|
||||
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
|
||||
if err != nil {
|
||||
return models.Cipher{}, "", err
|
||||
}
|
||||
|
||||
pubKey := signer.PublicKey()
|
||||
encryptedName, _ := crypto.EncryptWith([]byte(name), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedPublicKeyKey, _ := crypto.EncryptWith([]byte("public-key"), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedPublicKeyValue, _ := crypto.EncryptWith([]byte(string(ssh.MarshalAuthorizedKey(pubKey))), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedCustomTypeKey, _ := crypto.EncryptWith([]byte("custom-type"), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedCustomTypeValue, _ := crypto.EncryptWith([]byte("ssh-key"), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedPrivateKeyKey, _ := crypto.EncryptWith([]byte("private-key"), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
encryptedPrivateKeyValue, _ := crypto.EncryptWith([]byte(privateKey), crypto.AesCbc256_HmacSha256_B64, keyring.GetAccountKey())
|
||||
|
||||
cipher := models.Cipher{
|
||||
Type: models.CipherNote,
|
||||
Name: encryptedName,
|
||||
Notes: &encryptedPublicKeyValue,
|
||||
ID: nil,
|
||||
Favorite: false,
|
||||
OrganizationID: nil,
|
||||
SecureNote: &models.SecureNoteCipher{
|
||||
Type: 0,
|
||||
},
|
||||
Fields: []models.Field{
|
||||
{
|
||||
Type: 0,
|
||||
Name: encryptedCustomTypeKey,
|
||||
Value: encryptedCustomTypeValue,
|
||||
},
|
||||
{
|
||||
Type: 0,
|
||||
Name: encryptedPublicKeyKey,
|
||||
Value: encryptedPublicKeyValue,
|
||||
},
|
||||
{
|
||||
Type: 1,
|
||||
Name: encryptedPrivateKeyKey,
|
||||
Value: encryptedPrivateKeyValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return cipher, string(ssh.MarshalAuthorizedKey(pubKey)), nil
|
||||
}
|
||||
|
||||
func NewSSHKeyCipher(name string, keyring *crypto.Keyring) (models.Cipher, string, error) {
|
||||
var reader io.Reader = rand.Reader
|
||||
pub, priv, err := ed25519.GenerateKey(reader)
|
||||
|
||||
@ -72,5 +119,5 @@ func NewSSHKeyCipher(name string, keyring *crypto.Keyring) (models.Cipher, strin
|
||||
},
|
||||
}
|
||||
|
||||
return cipher, string(ssh.MarshalAuthorizedKey(publicKey))
|
||||
return cipher, string(ssh.MarshalAuthorizedKey(publicKey)), nil
|
||||
}
|
||||
|
@ -1,16 +1,27 @@
|
||||
//go:build freebsd || linux
|
||||
//go:build freebsd || linux || darwin
|
||||
|
||||
package pinentry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
|
||||
"github.com/twpayne/go-pinentry"
|
||||
)
|
||||
|
||||
func getBinaryClientOption() (clientOption pinentry.ClientOption) {
|
||||
binaryClientOption := pinentry.WithBinaryNameFromGnuPGAgentConf()
|
||||
if runtime.GOOS == "darwin" {
|
||||
binaryClientOption = pinentry.WithBinaryName("pinentry-mac")
|
||||
}
|
||||
return binaryClientOption
|
||||
}
|
||||
|
||||
func getPassword(title string, description string) (string, error) {
|
||||
binaryClientOption := getBinaryClientOption()
|
||||
|
||||
client, err := pinentry.NewClient(
|
||||
pinentry.WithBinaryNameFromGnuPGAgentConf(),
|
||||
binaryClientOption,
|
||||
pinentry.WithGPGTTY(),
|
||||
pinentry.WithTitle(title),
|
||||
pinentry.WithDesc(description),
|
||||
@ -43,8 +54,10 @@ func getApproval(title string, description string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
binaryClientOption := getBinaryClientOption()
|
||||
|
||||
client, err := pinentry.NewClient(
|
||||
pinentry.WithBinaryNameFromGnuPGAgentConf(),
|
||||
binaryClientOption,
|
||||
pinentry.WithGPGTTY(),
|
||||
pinentry.WithTitle(title),
|
||||
pinentry.WithDesc(description),
|
||||
|
@ -1,4 +1,4 @@
|
||||
//go:build windows || darwin
|
||||
//go:build windows
|
||||
|
||||
package pinentry
|
||||
|
||||
|
@ -55,9 +55,12 @@ func (s *SessionStore) CreateSession(pid int, parentpid int, grandparentpid int,
|
||||
|
||||
func (s *SessionStore) verifySession(ctx sockets.CallingContext, sessionType SessionType) bool {
|
||||
for _, session := range s.Store {
|
||||
if session.ParentPid == ctx.ParentProcessPid && session.GrandParentPid == ctx.GrandParentProcessPid && session.sessionType == sessionType {
|
||||
if session.Expires.After(time.Now()) {
|
||||
return true
|
||||
if session.sessionType == sessionType {
|
||||
// only check for ancestor if the session is not a ssh session
|
||||
if sessionType == SSHKey || (session.ParentPid == ctx.ParentProcessPid && session.GrandParentPid == ctx.GrandParentProcessPid) {
|
||||
if session.Expires.After(time.Now()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package vault
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sync"
|
||||
|
||||
"github.com/quexten/goldwarden/cli/agent/bitwarden/crypto"
|
||||
@ -17,10 +19,11 @@ type Vault struct {
|
||||
Keyring *crypto.Keyring
|
||||
logins map[string]models.Cipher
|
||||
secureNotes map[string]models.Cipher
|
||||
sshKeys map[string]models.Cipher
|
||||
sshKeyNoteIDs []string
|
||||
envCredentials map[string]string
|
||||
lastSynced int64
|
||||
websockedConnected bool
|
||||
websocketConnected bool
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
@ -29,10 +32,11 @@ func NewVault(keyring *crypto.Keyring) *Vault {
|
||||
Keyring: keyring,
|
||||
logins: make(map[string]models.Cipher),
|
||||
secureNotes: make(map[string]models.Cipher),
|
||||
sshKeys: make(map[string]models.Cipher),
|
||||
sshKeyNoteIDs: make([]string, 0),
|
||||
envCredentials: make(map[string]string),
|
||||
lastSynced: 0,
|
||||
websockedConnected: false,
|
||||
websocketConnected: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +94,12 @@ func (vault *Vault) AddOrUpdateSecureNote(cipher models.Cipher) {
|
||||
vault.unlockMutex()
|
||||
}
|
||||
|
||||
func (vault *Vault) AddOrUpdateSSHKey(cipher models.Cipher) {
|
||||
vault.lockMutex()
|
||||
vault.sshKeys[cipher.ID.String()] = cipher
|
||||
vault.unlockMutex()
|
||||
}
|
||||
|
||||
func (vault *Vault) isEnv(cipher models.Cipher) (string, bool) {
|
||||
if cipher.Type != models.CipherNote {
|
||||
return "", false
|
||||
@ -174,6 +184,26 @@ type SSHKey struct {
|
||||
PublicKey string
|
||||
}
|
||||
|
||||
func extractKeyMarker(text, pattern string) (string, string, error) {
|
||||
re := regexp.MustCompile(pattern)
|
||||
match := re.FindStringIndex(text)
|
||||
|
||||
if match != nil {
|
||||
// Extract the matched text
|
||||
extracted := re.FindString(text[match[0]:match[1]])
|
||||
if match[0] == 0 {
|
||||
// begin marker
|
||||
return extracted, text[match[1]:], nil
|
||||
} else if match[1] == len(strings.TrimRight(text, "\n\r ")) {
|
||||
// end marker
|
||||
return extracted, text[:match[0]], nil
|
||||
}
|
||||
return "", text, fmt.Errorf("Token found is neither at the beginning nor end: pattern: %s. match idx: %s", pattern, match)
|
||||
}
|
||||
|
||||
return "", text, fmt.Errorf("No match found in pattern %s", pattern)
|
||||
}
|
||||
|
||||
func (vault *Vault) GetSSHKeys() []SSHKey {
|
||||
vault.lockMutex()
|
||||
defer vault.unlockMutex()
|
||||
@ -211,11 +241,19 @@ func (vault *Vault) GetSSHKeys() []SSHKey {
|
||||
}
|
||||
}
|
||||
|
||||
privateKey = strings.Replace(privateKey, "-----BEGIN OPENSSH PRIVATE KEY-----", "", 1)
|
||||
privateKey = strings.Replace(privateKey, "-----END OPENSSH PRIVATE KEY-----", "", 1)
|
||||
beginMarker, privateKey, err := extractKeyMarker(privateKey, `-----\w*BEGIN [a-zA-Z ]+\w*-----`)
|
||||
if err != nil {
|
||||
vaultLog.Error("Failed for note %s: %s", vault.secureNotes[id].Name, err.Error())
|
||||
continue
|
||||
}
|
||||
endMarker, privateKey, err := extractKeyMarker(privateKey, `-----\w*END [a-zA-Z ]+\w*-----`)
|
||||
if err != nil {
|
||||
vaultLog.Error("Failed for note %s: %s", vault.secureNotes[id].Name, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
pkParts := strings.Join(strings.Split(privateKey, " "), "\n")
|
||||
privateKeyString := "-----BEGIN OPENSSH PRIVATE KEY-----" + pkParts + "-----END OPENSSH PRIVATE KEY-----"
|
||||
privateKeyString := beginMarker + pkParts + endMarker
|
||||
|
||||
decryptedTitle, err := crypto.DecryptWith(vault.secureNotes[id].Name, key)
|
||||
if err != nil {
|
||||
@ -228,6 +266,20 @@ func (vault *Vault) GetSSHKeys() []SSHKey {
|
||||
PublicKey: string(publicKey),
|
||||
})
|
||||
}
|
||||
|
||||
for id, _ := range vault.sshKeys {
|
||||
key, _ := vault.sshKeys[id].GetKeyForCipher(*vault.Keyring)
|
||||
privKey, _ := crypto.DecryptWith(vault.sshKeys[id].SSHKey.PrivateKey, key)
|
||||
pubKey, _ := crypto.DecryptWith(vault.sshKeys[id].SSHKey.PublicKey, key)
|
||||
name, _ := crypto.DecryptWith(vault.sshKeys[id].Name, key)
|
||||
|
||||
sshKeys = append(sshKeys, SSHKey{
|
||||
Name: string(name),
|
||||
Key: string(privKey),
|
||||
PublicKey: string(pubKey),
|
||||
})
|
||||
}
|
||||
|
||||
return sshKeys
|
||||
}
|
||||
|
||||
@ -424,7 +476,7 @@ func (vault *Vault) GetLastSynced() int64 {
|
||||
|
||||
func (vault *Vault) SetWebsocketConnected(connected bool) {
|
||||
vault.lockMutex()
|
||||
vault.websockedConnected = connected
|
||||
vault.websocketConnected = connected
|
||||
vault.unlockMutex()
|
||||
}
|
||||
|
||||
@ -432,5 +484,5 @@ func (vault *Vault) IsWebsocketConnected() bool {
|
||||
vault.lockMutex()
|
||||
defer vault.unlockMutex()
|
||||
|
||||
return vault.websockedConnected
|
||||
return vault.websocketConnected
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@ -18,12 +19,12 @@ var sshCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
// runCmd represents the run command
|
||||
// sshAddCmd represents the ssh add command
|
||||
var sshAddCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
Short: "Runs a command with environment variables from your vault",
|
||||
Long: `Runs a command with environment variables from your vault.
|
||||
The variables are stored as a secure note. Consult the documentation for more information.`,
|
||||
Short: "Creates a new SSH key and adds it to the SSH Agent.",
|
||||
Long: `Creates a new SSH key and adds it to the SSH Agent.
|
||||
The key is stored as a secure note. Consult the documentation for more information.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := loginIfRequired()
|
||||
if err != nil {
|
||||
@ -92,6 +93,64 @@ var listSSHCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var importSSHCmd = &cobra.Command{
|
||||
Use: "import",
|
||||
Short: "Imports an SSH key into your vault",
|
||||
Long: `Imports an SSH key into your vault.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
fmt.Println("Error: No filename for SSH key specified")
|
||||
return
|
||||
}
|
||||
|
||||
filename := args[0]
|
||||
fmt.Println("Importing SSH key from " + filename)
|
||||
|
||||
name, _ := cmd.Flags().GetString("name")
|
||||
if name == "" {
|
||||
name = "Imported SSH Key"
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
fmt.Println("Error: File does not exist")
|
||||
return
|
||||
}
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
fmt.Println("Error: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(file)
|
||||
key := buf.String()
|
||||
|
||||
result, err := commandClient.SendToAgent(messages.ImportSSHKeyRequest{
|
||||
Key: key,
|
||||
Name: name,
|
||||
})
|
||||
if err != nil {
|
||||
handleSendToAgentError(err)
|
||||
return
|
||||
}
|
||||
|
||||
switch result.(type) {
|
||||
case messages.ImportSSHKeyResponse:
|
||||
response := result.(messages.ImportSSHKeyResponse)
|
||||
if response.Success {
|
||||
fmt.Println("Success")
|
||||
} else {
|
||||
fmt.Println("Error: " + response.ErrorMsg)
|
||||
}
|
||||
return
|
||||
case messages.ActionResponse:
|
||||
fmt.Println("Error: " + result.(messages.ActionResponse).Message)
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(sshCmd)
|
||||
sshCmd.AddCommand(sshAddCmd)
|
||||
@ -99,4 +158,6 @@ func init() {
|
||||
_ = sshAddCmd.MarkFlagRequired("name")
|
||||
sshAddCmd.PersistentFlags().Bool("clipboard", false, "Copy the public key to the clipboard")
|
||||
sshCmd.AddCommand(listSSHCmd)
|
||||
importSSHCmd.PersistentFlags().String("name", "", "")
|
||||
sshCmd.AddCommand(importSSHCmd)
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ var statusCmd = &cobra.Command{
|
||||
response["loginEntries"] = status.NumberOfLogins
|
||||
response["noteEntries"] = status.NumberOfNotes
|
||||
response["lastSynced"] = time.Unix(status.LastSynced, 0).String()
|
||||
response["websocketConnected"] = status.WebsockedConnected
|
||||
response["websocketConnected"] = status.WebsocketConnected
|
||||
response["pinSet"] = status.PinSet
|
||||
response["loggedIn"] = status.LoggedIn
|
||||
responseJSON, _ := json.Marshal(response)
|
||||
|
@ -17,6 +17,16 @@ type GetSSHKeysResponse struct {
|
||||
Keys []string
|
||||
}
|
||||
|
||||
type ImportSSHKeyRequest struct {
|
||||
Key string
|
||||
Name string
|
||||
}
|
||||
|
||||
type ImportSSHKeyResponse struct {
|
||||
Success bool
|
||||
ErrorMsg string
|
||||
}
|
||||
|
||||
func init() {
|
||||
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||
var req CreateSSHKeyRequest
|
||||
@ -53,4 +63,22 @@ func init() {
|
||||
}
|
||||
return req, nil
|
||||
}, GetSSHKeysResponse{})
|
||||
|
||||
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||
var req ImportSSHKeyRequest
|
||||
err := json.Unmarshal(payload, &req)
|
||||
if err != nil {
|
||||
panic("Unmarshal: " + err.Error())
|
||||
}
|
||||
return req, nil
|
||||
}, ImportSSHKeyRequest{})
|
||||
|
||||
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||
var req ImportSSHKeyResponse
|
||||
err := json.Unmarshal(payload, &req)
|
||||
if err != nil {
|
||||
panic("Unmarshal: " + err.Error())
|
||||
}
|
||||
return req, nil
|
||||
}, ImportSSHKeyResponse{})
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ type VaultStatusResponse struct {
|
||||
NumberOfLogins int
|
||||
NumberOfNotes int
|
||||
LastSynced int64
|
||||
WebsockedConnected bool
|
||||
WebsocketConnected bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
16
go.mod
16
go.mod
@ -13,21 +13,21 @@ require (
|
||||
github.com/gen2brain/beeep v0.0.0-20240112042604-c7bb2cd88fea
|
||||
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/icza/gox v0.2.0
|
||||
github.com/keybase/client/go v0.0.0-20240424154521-52f30ea26cb1
|
||||
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
|
||||
github.com/rymdport/portal v0.2.2
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/rymdport/portal v0.2.6
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4
|
||||
github.com/tink-crypto/tink-go/v2 v2.1.0
|
||||
github.com/tink-crypto/tink-go/v2 v2.2.0
|
||||
github.com/twpayne/go-pinentry v0.3.0
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
golang.org/x/crypto v0.22.0
|
||||
golang.org/x/crypto v0.28.0
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
|
||||
golang.org/x/sys v0.19.0
|
||||
golang.org/x/sys v0.26.0
|
||||
)
|
||||
|
||||
require (
|
||||
@ -56,5 +56,3 @@ require (
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/rymdport/portal => github.com/quexten/portal v0.0.0-20240429200240-156297fa11c5
|
||||
|
38
go.sum
38
go.sum
@ -15,7 +15,7 @@ github.com/awnumar/memcall v0.2.0/go.mod h1:S911igBPR9CThzd/hYQQmTc9SWNu3ZHIlCGa
|
||||
github.com/awnumar/memguard v0.22.5 h1:PH7sbUVERS5DdXh3+mLo8FDcl1eIeVjJVYMnyuYpvuI=
|
||||
github.com/awnumar/memguard v0.22.5/go.mod h1:+APmZGThMBWjnMlKiSM1X7MVpbIVewen2MTkqWkA/zE=
|
||||
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.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -32,12 +32,12 @@ github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5 h1:K7KEFpKgVcjj98jOu2Z3xMBTtTwfYVT90Zmo3ZuWmbE=
|
||||
github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5/go.mod h1:VbcN86fRkkUMPX2ufM85Um8zFndLZswoIW1eYtpAcVk=
|
||||
github.com/icza/gox v0.2.0 h1:+0N8PCt9/QSx+k0dqe/wdlXJNR/haaPsPwrTJTNDeyk=
|
||||
github.com/icza/gox v0.2.0/go.mod h1:rVecw5Q6POJAWBcXgCZdAtwK/hmoNehxCkAP3sMnOIc=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/keybase/backoff v1.0.1-0.20160517061000-726b63b835ec h1:D6qL2WCnAuxucGbmL+mDW8IKRK1pex+R1fw5rKa9nXc=
|
||||
@ -76,8 +76,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quexten/portal v0.0.0-20240429200240-156297fa11c5 h1:roVJ7WlvNo3R4NfVLysq3siLrVZgotg/JZkZ1dQEZ5k=
|
||||
github.com/quexten/portal v0.0.0-20240429200240-156297fa11c5/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||
github.com/reiver/go-oi v1.0.0 h1:nvECWD7LF+vOs8leNGV/ww+F2iZKf3EYjYZ527turzM=
|
||||
github.com/reiver/go-oi v1.0.0/go.mod h1:RrDBct90BAhoDTxB1fenZwfykqeGvhI6LsNfStJoEkI=
|
||||
github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e h1:quuzZLi72kkJjl+f5AQ93FMcadG19WkS7MO6TXFOSas=
|
||||
@ -86,8 +84,10 @@ github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
|
||||
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/rymdport/portal v0.2.6 h1:HWmU3gORu7vWcpr7VSwUS2Xx1HtJXVcUuTqEZcMEsIg=
|
||||
github.com/rymdport/portal v0.2.6/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@ -98,16 +98,16 @@ github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG0
|
||||
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
|
||||
github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 h1:Gz0rz40FvFVLTBk/K8UNAenb36EbDSnh+q7Z9ldcC8w=
|
||||
github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4/go.mod h1:phI29ccmHQBc+wvroosENp1IF9195449VDnFDhJ4rJU=
|
||||
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.2.0 h1:L2Da0F2Udh2agtKztdr69mV/KpnY3/lGTkMgLTVIXlA=
|
||||
github.com/tink-crypto/tink-go/v2 v2.2.0/go.mod h1:JJ6PomeNPF3cJpfWC0lgyTES6zpJILkAX0cJNwlS3xU=
|
||||
github.com/twpayne/go-pinentry v0.3.0 h1:Rr+fEOZXmeItOb4thjeVaBWJKB9Xa/eojolycyF/26c=
|
||||
github.com/twpayne/go-pinentry v0.3.0/go.mod h1:iOIZD+9np/2V24OdCGos7Y1/xX90wc6VEAZsgb+r9D4=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
@ -118,12 +118,12 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
|
||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
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.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
@ -102,7 +102,7 @@ modules:
|
||||
- cp -R ./gui/* /app/bin
|
||||
- chmod +x /app/bin/goldwarden_ui_main.py
|
||||
- install -D ./gui/com.quexten.Goldwarden.desktop /app/share/applications/com.quexten.Goldwarden.desktop
|
||||
- install -D ./gui/goldwarden.svg /app/share/icons/hicolor/scalable/apps/com.quexten.Goldwarden.svg
|
||||
- install -D ./gui/com.quexten.Goldwarden.svg /app/share/icons/hicolor/scalable/apps/com.quexten.Goldwarden.svg
|
||||
- install -Dm644 ./gui/com.quexten.Goldwarden.metainfo.xml -t /app/share/metainfo/
|
||||
- blueprint-compiler batch-compile /app/bin/src/gui/.templates/ /app/bin/src/gui/ /app/bin/src/gui/*.blp
|
||||
sources:
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
12
gui/goldwarden_ui_main.py
Normal file → Executable file
12
gui/goldwarden_ui_main.py
Normal file → Executable file
@ -1,4 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
import src.linux.main as linux_main
|
||||
|
||||
linux_main.main()
|
||||
import platform
|
||||
|
||||
if platform.system() == 'Darwin':
|
||||
import src.macos.main as macos_main
|
||||
macos_main.main()
|
||||
elif platform.system() == 'Linux':
|
||||
import src.linux.main as linux_main
|
||||
linux_main.main()
|
||||
else:
|
||||
print("Unsupported OS " + platform.system() + "... exiting...")
|
@ -47,15 +47,45 @@ class GoldwardenLoginApp(Adw.Application):
|
||||
|
||||
def on_login(self):
|
||||
email = self.email_row.get_text()
|
||||
client_id = self.client_id_row.get_text()
|
||||
client_secret = self.client_secret_row.get_text()
|
||||
client_id = self.client_id_row.get_text().strip()
|
||||
client_secret = self.client_secret_row.get_text().strip()
|
||||
server = self.server_row.get_text()
|
||||
print("setting server to", server, "with result", goldwarden.set_server(server))
|
||||
try:
|
||||
goldwarden.set_server(server)
|
||||
except:
|
||||
print("set server failed")
|
||||
dialog = Adw.MessageDialog.new(self.window,
|
||||
"Failed to set server",
|
||||
"The server you entered is invalid, please try again.",
|
||||
)
|
||||
dialog.add_response("ok", "Dismiss")
|
||||
dialog.present()
|
||||
return
|
||||
|
||||
if client_id != "":
|
||||
goldwarden.set_client_id(client_id)
|
||||
if client_secret != "":
|
||||
goldwarden.set_client_secret(client_secret)
|
||||
goldwarden.login_with_password(email, "")
|
||||
|
||||
try:
|
||||
goldwarden.login_with_password(email, "")
|
||||
except Exception as e:
|
||||
if "errorbadpassword" in str(e):
|
||||
dialog = Adw.MessageDialog.new(self.window, "Bad Password", "The username or password you entered is incorrect.")
|
||||
dialog.add_response("ok", "Dismiss")
|
||||
dialog.present()
|
||||
return
|
||||
if "errorcaptcha" in str(e):
|
||||
dialog = Adw.MessageDialog.new(self.window, "Unusual traffic error", "Traffic is unusual, please set up api client id and client secret.")
|
||||
dialog.add_response("ok", "Dismiss")
|
||||
dialog.present()
|
||||
return
|
||||
if "errortotp" in str(e):
|
||||
dialog = Adw.MessageDialog.new(self.window, "TOTP Invalid", "The TOTP code you entered is invalid.")
|
||||
dialog.add_response("ok", "Dismiss")
|
||||
dialog.present()
|
||||
return
|
||||
|
||||
self.window.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -1,10 +1,10 @@
|
||||
import gi
|
||||
gi.require_version('Gtk', '4.0')
|
||||
gi.require_version('Adw', '1')
|
||||
gi.require_version('Notify', '0.7')
|
||||
# gi.require_version('Notify', '0.7')
|
||||
import gc
|
||||
import time
|
||||
from gi.repository import Gtk, Adw, GLib, Notify, Gdk
|
||||
from gi.repository import Gtk, Adw, GLib, Gdk
|
||||
from ..services import goldwarden
|
||||
from ..services.autotype import autotype
|
||||
from threading import Thread
|
||||
@ -12,7 +12,6 @@ from .resource_loader import load_template
|
||||
import sys
|
||||
import os
|
||||
from ..services import totp
|
||||
Notify.init("Goldwarden")
|
||||
|
||||
class GoldwardenQuickAccessApp(Adw.Application):
|
||||
def __init__(self, **kwargs):
|
||||
@ -115,8 +114,8 @@ class GoldwardenQuickAccessApp(Adw.Application):
|
||||
|
||||
def run_autotype(self, text):
|
||||
def perform_autotype(text):
|
||||
self.window.hide()
|
||||
time.sleep(0.1)
|
||||
GLib.idle_add(self.window.hide)
|
||||
time.sleep(2)
|
||||
autotype.autotype(text)
|
||||
time.sleep(0.1)
|
||||
os._exit(0)
|
||||
@ -148,7 +147,7 @@ class GoldwardenQuickAccessApp(Adw.Application):
|
||||
self.filtered_logins = self.filtered_logins[0:7]
|
||||
|
||||
def render_list(self):
|
||||
if len(self.filtered_logins) > 1:
|
||||
if len(self.filtered_logins) > 0:
|
||||
self.results_list.set_visible(True)
|
||||
while self.results_list.get_first_child() != None:
|
||||
self.results_list.remove(self.results_list.get_first_child())
|
||||
|
@ -110,7 +110,7 @@ Adw.ApplicationWindow window {
|
||||
icon-name: "emblem-synchronizing-symbolic";
|
||||
}
|
||||
Adw.ActionRow websocket_connected_row {
|
||||
title: "Websocked Connected";
|
||||
title: "Websocket Connected";
|
||||
subtitle: "False";
|
||||
}
|
||||
Adw.ActionRow logins_row {
|
||||
|
@ -101,8 +101,7 @@ class GoldwardenSettingsApp(Adw.Application):
|
||||
if status == None:
|
||||
is_daemon_running = goldwarden.is_daemon_running()
|
||||
if not is_daemon_running:
|
||||
self.status_row.set_subtitle("Daemon not running")
|
||||
self.vault_status_icon.set_icon("dialog-error", "error")
|
||||
print("Daemon not running")
|
||||
return
|
||||
|
||||
logged_in = status["loggedIn"]
|
||||
|
@ -7,6 +7,7 @@ gi.require_version('Gtk', '4.0')
|
||||
gi.require_version('Adw', '1')
|
||||
from gi.repository import GLib, Gio
|
||||
import sys
|
||||
from threading import Timer
|
||||
|
||||
def set_status(message):
|
||||
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
|
||||
@ -29,9 +30,13 @@ def set_status(message):
|
||||
sys.exit(0)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sys.exit(0)
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
set_status(sys.argv[1])
|
||||
|
||||
thread = Timer(10, sys.exit, [0])
|
||||
thread.start()
|
||||
|
||||
loop = GLib.MainLoop()
|
||||
loop.run()
|
||||
|
30
gui/src/macos/main.py
Normal file
30
gui/src/macos/main.py
Normal file
@ -0,0 +1,30 @@
|
||||
import sys
|
||||
import subprocess
|
||||
import os
|
||||
import secrets
|
||||
from src.services import goldwarden
|
||||
from src.services import pinentry
|
||||
import time
|
||||
|
||||
root_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir))
|
||||
|
||||
def main():
|
||||
token = secrets.token_hex(32)
|
||||
if not os.environ.get("GOLDWARDEN_DAEMON_AUTH_TOKEN") == None:
|
||||
token = os.environ["GOLDWARDEN_DAEMON_AUTH_TOKEN"]
|
||||
print("Starting Goldwarden GUI")
|
||||
goldwarden.run_daemon_background(token)
|
||||
time.sleep(1)
|
||||
#pinentry.daemonize()
|
||||
if not "--hidden" in sys.argv:
|
||||
p = subprocess.Popen(["python3", "-m", "src.gui.settings"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=root_path, start_new_session=True)
|
||||
p.stdin.write(f"{token}\n".encode())
|
||||
p.stdin.flush()
|
||||
# print stdout
|
||||
while True:
|
||||
line = p.stderr.readline()
|
||||
if not line:
|
||||
break
|
||||
print(line.decode().strip())
|
||||
while True:
|
||||
time.sleep(60)
|
@ -1,5 +1,5 @@
|
||||
from ..goldwarden import autotype
|
||||
|
||||
def libportal_autotype(text):
|
||||
def autotype_libportal(text):
|
||||
print("autotypeing with libportal")
|
||||
goldwarden.autotype(text)
|
||||
autotype(text)
|
||||
|
@ -2,4 +2,7 @@ import pyautogui
|
||||
|
||||
def autotype_pyautogui(text):
|
||||
print("autotypeing with pyautogui")
|
||||
pyautogui.write(text, interval=0.02)
|
||||
pyautogui.write(text, interval=0.02)
|
||||
|
||||
if __name__ == "__main__":
|
||||
autotype_pyautogui("hello world")
|
@ -71,7 +71,9 @@ def set_vault_url(url):
|
||||
send_authenticated_command(f"config set-vault-url {url}")
|
||||
|
||||
def set_server(url):
|
||||
send_authenticated_command(f"config set-server {url}")
|
||||
result = send_authenticated_command(f"config set-server {url}")
|
||||
if result.strip() != "Done":
|
||||
raise Exception("Failed to set server")
|
||||
|
||||
def get_environment():
|
||||
result = send_authenticated_command(f"config get-environment")
|
||||
@ -81,16 +83,19 @@ def get_environment():
|
||||
return None
|
||||
|
||||
def set_client_id(client_id):
|
||||
send_authenticated_command(f"config set-client-id \"{client_id}\"")
|
||||
return send_authenticated_command(f"config set-client-id {client_id}")
|
||||
|
||||
def set_client_secret(client_secret):
|
||||
send_authenticated_command(f"config set-client-secret \"{client_secret}\"")
|
||||
return send_authenticated_command(f"config set-client-secret {client_secret}")
|
||||
|
||||
def login_with_password(email, password):
|
||||
result = send_authenticated_command(f"vault login --email {email}")
|
||||
if not "Logged in" in result:
|
||||
return "badpass"
|
||||
return "ok"
|
||||
if "Login failed" in result and "username or password" in result.lower():
|
||||
raise Exception("errorbadpassword")
|
||||
if "Login failed" in result and ("error code 7" in result.lower() or "error code 6" in result.lower()):
|
||||
raise Exception("errorcaptcha")
|
||||
if "Login failed" in result and "two-factor" in result.lower():
|
||||
raise Exception("errortotp")
|
||||
|
||||
def login_passwordless(email):
|
||||
send_authenticated_command(f"vault login --email {email} --passwordless")
|
||||
|
Loading…
x
Reference in New Issue
Block a user