Add prototype GTK UI
This commit is contained in:
parent
dcc2fb8bdc
commit
6f30d75b08
|
@ -1,2 +1,3 @@
|
||||||
.vscode
|
.vscode
|
||||||
goldwarden*
|
goldwarden
|
||||||
|
__pycache__
|
|
@ -85,9 +85,9 @@ Run a command with injected environment variables
|
||||||
goldwarden run -- <command>
|
goldwarden run -- <command>
|
||||||
```
|
```
|
||||||
|
|
||||||
Autofill
|
Autofill (Flatpak only?)
|
||||||
```
|
```
|
||||||
goldwarden autofill --layout <keyboard-layout>
|
dbus-send --type=method_call --dest=com.quexten.goldwarden /com/quexten/goldwarden com.quexten.goldwarden.Autofill.autofill
|
||||||
```
|
```
|
||||||
(Create a hotkey for this depending on your desktop environment)
|
(Create a hotkey for this depending on your desktop environment)
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ func handleGetLoginCipher(request messages.IPCMessage, cfg *config.Config, vault
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleListLoginsRequest(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
func handleListLoginsRequest(request messages.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
||||||
if approved, err := pinentry.GetApproval("Approve List Credentials", fmt.Sprintf("%s on %s>%s>%s is trying to list credentials (name & username)", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved {
|
if approved, err := pinentry.GetApproval("Approve List Credentials", fmt.Sprintf("%s on %s>%s>%s is trying access all credentials", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved {
|
||||||
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
response, err = messages.IPCMessageFromPayload(messages.ActionResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
Message: "not approved",
|
Message: "not approved",
|
||||||
|
@ -123,6 +123,7 @@ func handleListLoginsRequest(request messages.IPCMessage, cfg *config.Config, va
|
||||||
|
|
||||||
var decryptedName []byte = []byte{}
|
var decryptedName []byte = []byte{}
|
||||||
var decryptedUsername []byte = []byte{}
|
var decryptedUsername []byte = []byte{}
|
||||||
|
var decryptedPassword []byte = []byte{}
|
||||||
|
|
||||||
if !login.Name.IsNull() {
|
if !login.Name.IsNull() {
|
||||||
decryptedName, err = crypto.DecryptWith(login.Name, key)
|
decryptedName, err = crypto.DecryptWith(login.Name, key)
|
||||||
|
@ -140,10 +141,19 @@ func handleListLoginsRequest(request messages.IPCMessage, cfg *config.Config, va
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !login.Login.Password.IsNull() {
|
||||||
|
decryptedPassword, err = crypto.DecryptWith(login.Login.Password, key)
|
||||||
|
if err != nil {
|
||||||
|
actionsLog.Warn("Could not decrypt login:" + err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decryptedLoginCiphers = append(decryptedLoginCiphers, messages.DecryptedLoginCipher{
|
decryptedLoginCiphers = append(decryptedLoginCiphers, messages.DecryptedLoginCipher{
|
||||||
Name: string(decryptedName),
|
Name: string(decryptedName),
|
||||||
Username: string(decryptedUsername),
|
Username: string(decryptedUsername),
|
||||||
UUID: login.ID.String(),
|
UUID: login.ID.String(),
|
||||||
|
Password: string(decryptedPassword),
|
||||||
})
|
})
|
||||||
|
|
||||||
// prevent deadlock from enclaves
|
// prevent deadlock from enclaves
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
//go:build !noautofill
|
|
||||||
|
|
||||||
package autofill
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/atotto/clipboard"
|
|
||||||
"github.com/quexten/goldwarden/autofill/autotype"
|
|
||||||
"github.com/quexten/goldwarden/client"
|
|
||||||
"github.com/quexten/goldwarden/ipc/messages"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetLoginByUUID(uuid string, client client.Client) (messages.DecryptedLoginCipher, error) {
|
|
||||||
resp, err := client.SendToAgent(messages.GetLoginRequest{
|
|
||||||
UUID: uuid,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return messages.DecryptedLoginCipher{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch resp.(type) {
|
|
||||||
case messages.GetLoginResponse:
|
|
||||||
castedResponse := (resp.(messages.GetLoginResponse))
|
|
||||||
return castedResponse.Result, nil
|
|
||||||
case messages.ActionResponse:
|
|
||||||
castedResponse := (resp.(messages.ActionResponse))
|
|
||||||
return messages.DecryptedLoginCipher{}, errors.New("Error: " + castedResponse.Message)
|
|
||||||
default:
|
|
||||||
return messages.DecryptedLoginCipher{}, errors.New("Wrong response type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListLogins(client client.Client) ([]messages.DecryptedLoginCipher, error) {
|
|
||||||
resp, err := client.SendToAgent(messages.ListLoginsRequest{})
|
|
||||||
if err != nil {
|
|
||||||
return []messages.DecryptedLoginCipher{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch resp.(type) {
|
|
||||||
case messages.GetLoginsResponse:
|
|
||||||
castedResponse := (resp.(messages.GetLoginsResponse))
|
|
||||||
return castedResponse.Result, nil
|
|
||||||
case messages.ActionResponse:
|
|
||||||
castedResponse := (resp.(messages.ActionResponse))
|
|
||||||
return []messages.DecryptedLoginCipher{}, errors.New("Error: " + castedResponse.Message)
|
|
||||||
default:
|
|
||||||
return []messages.DecryptedLoginCipher{}, errors.New("Wrong response type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Run(layout string, client client.Client) {
|
|
||||||
logins, err := ListLogins(client)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
autofillEntries := []AutofillEntry{}
|
|
||||||
for _, login := range logins {
|
|
||||||
autofillEntries = append(autofillEntries, AutofillEntry{
|
|
||||||
Name: login.Name,
|
|
||||||
Username: login.Username,
|
|
||||||
UUID: login.UUID,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
RunAutofill(autofillEntries, func(uuid string, c chan bool) {
|
|
||||||
login, err := GetLoginByUUID(uuid, client)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
autotype.TypeString(string(login.Username)+"\t"+string(login.Password), layout)
|
|
||||||
|
|
||||||
clipboard.WriteAll(login.TwoFactorCode)
|
|
||||||
c <- true
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,384 +0,0 @@
|
||||||
package uinput
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/bendahl/uinput"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Dvorak struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d Dvorak) TypeKey(key Key, keyboard uinput.Keyboard) error {
|
|
||||||
var err error
|
|
||||||
switch key {
|
|
||||||
case KeyA:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyA)
|
|
||||||
break
|
|
||||||
case KeyAUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyA)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyB:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyN)
|
|
||||||
break
|
|
||||||
case KeyBUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyN)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyC:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyI)
|
|
||||||
break
|
|
||||||
case KeyCUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyI)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyD:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyH)
|
|
||||||
break
|
|
||||||
case KeyDUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyH)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyE:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyD)
|
|
||||||
break
|
|
||||||
case KeyEUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
err = keyboard.KeyPress(uinput.KeyD)
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyF:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyY)
|
|
||||||
break
|
|
||||||
case KeyFUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyY)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyG:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyU)
|
|
||||||
break
|
|
||||||
case KeyGUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyU)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyH:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyJ)
|
|
||||||
break
|
|
||||||
case KeyHUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyJ)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyI:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyG)
|
|
||||||
break
|
|
||||||
case KeyIUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyG)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyJ:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyC)
|
|
||||||
break
|
|
||||||
case KeyJUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyC)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyK:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyV)
|
|
||||||
break
|
|
||||||
case KeyKUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyV)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyL:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyP)
|
|
||||||
break
|
|
||||||
case KeyLUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyP)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyM:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyM)
|
|
||||||
break
|
|
||||||
case KeyMUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyM)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyN:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyL)
|
|
||||||
break
|
|
||||||
case KeyNUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyL)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyO:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyS)
|
|
||||||
break
|
|
||||||
case KeyOUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyS)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyP:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyR)
|
|
||||||
break
|
|
||||||
case KeyPUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyR)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyQ:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyX)
|
|
||||||
break
|
|
||||||
case KeyQUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyX)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyR:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyO)
|
|
||||||
break
|
|
||||||
case KeyRUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyO)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyS:
|
|
||||||
err = keyboard.KeyPress(uinput.KeySemicolon)
|
|
||||||
break
|
|
||||||
case KeySUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeySemicolon)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyT:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyK)
|
|
||||||
break
|
|
||||||
case KeyTUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyK)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyU:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyF)
|
|
||||||
break
|
|
||||||
case KeyUUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyF)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyV:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyDot)
|
|
||||||
break
|
|
||||||
case KeyVUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyDot)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyW:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyComma)
|
|
||||||
break
|
|
||||||
case KeyWUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyComma)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyX:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyB)
|
|
||||||
break
|
|
||||||
case KeyXUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyB)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyY:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyT)
|
|
||||||
break
|
|
||||||
case KeyYUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyT)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyZ:
|
|
||||||
err = keyboard.KeyPress(uinput.KeySlash)
|
|
||||||
break
|
|
||||||
case KeyZUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeySlash)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case Key1:
|
|
||||||
err = keyboard.KeyPress(uinput.Key1)
|
|
||||||
break
|
|
||||||
case Key2:
|
|
||||||
err = keyboard.KeyPress(uinput.Key2)
|
|
||||||
break
|
|
||||||
case Key3:
|
|
||||||
err = keyboard.KeyPress(uinput.Key3)
|
|
||||||
break
|
|
||||||
case Key4:
|
|
||||||
err = keyboard.KeyPress(uinput.Key4)
|
|
||||||
break
|
|
||||||
case Key5:
|
|
||||||
err = keyboard.KeyPress(uinput.Key5)
|
|
||||||
break
|
|
||||||
case Key6:
|
|
||||||
err = keyboard.KeyPress(uinput.Key6)
|
|
||||||
break
|
|
||||||
case Key7:
|
|
||||||
err = keyboard.KeyPress(uinput.Key7)
|
|
||||||
break
|
|
||||||
case Key8:
|
|
||||||
err = keyboard.KeyPress(uinput.Key8)
|
|
||||||
break
|
|
||||||
case Key9:
|
|
||||||
err = keyboard.KeyPress(uinput.Key9)
|
|
||||||
break
|
|
||||||
case Key0:
|
|
||||||
err = keyboard.KeyPress(uinput.Key0)
|
|
||||||
break
|
|
||||||
case KeyTab:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyTab)
|
|
||||||
break
|
|
||||||
case KeyHyphen:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyApostrophe)
|
|
||||||
break
|
|
||||||
case KeyExclamationMark:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key1)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyAtSign:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key2)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyHash:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key3)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyDollar:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key4)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyPercent:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key5)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyCaret:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key6)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyAmpersand:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key7)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyAsterisk:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key8)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyDot:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyE)
|
|
||||||
break
|
|
||||||
case KeyComma:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyW)
|
|
||||||
break
|
|
||||||
case KeyQuestionMark:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyLeftbrace)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeySemicolon:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyZ)
|
|
||||||
break
|
|
||||||
case KeyColon:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyZ)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeySlash:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyLeftbrace)
|
|
||||||
break
|
|
||||||
case KeyApostrophe:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyQ)
|
|
||||||
break
|
|
||||||
case KeySpace:
|
|
||||||
err = keyboard.KeyPress(uinput.KeySpace)
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
fmt.Println("Unknown key: ", key)
|
|
||||||
fmt.Println("Please add it to the dvorak layout")
|
|
||||||
return errors.New("Unknown key")
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
DefaultLayoutRegistry.Register("dvorak", Dvorak{})
|
|
||||||
}
|
|
|
@ -1,387 +0,0 @@
|
||||||
package uinput
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/bendahl/uinput"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Qwerty struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d Qwerty) TypeKey(key Key, keyboard uinput.Keyboard) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
switch key {
|
|
||||||
case KeyA:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyA)
|
|
||||||
break
|
|
||||||
case KeyAUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyA)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyB:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyB)
|
|
||||||
break
|
|
||||||
case KeyBUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyB)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyC:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyC)
|
|
||||||
break
|
|
||||||
case KeyCUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyC)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyD:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyD)
|
|
||||||
break
|
|
||||||
case KeyDUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyD)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyE:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyE)
|
|
||||||
break
|
|
||||||
case KeyEUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyE)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyF:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyF)
|
|
||||||
break
|
|
||||||
case KeyFUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyF)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyG:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyG)
|
|
||||||
break
|
|
||||||
case KeyGUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyG)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyH:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyH)
|
|
||||||
break
|
|
||||||
case KeyHUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyH)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyI:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyI)
|
|
||||||
break
|
|
||||||
case KeyIUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyI)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyJ:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyJ)
|
|
||||||
break
|
|
||||||
case KeyJUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyJ)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyK:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyK)
|
|
||||||
break
|
|
||||||
case KeyKUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyK)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyL:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyL)
|
|
||||||
break
|
|
||||||
case KeyLUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyL)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyM:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyM)
|
|
||||||
break
|
|
||||||
case KeyMUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyM)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyN:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyN)
|
|
||||||
break
|
|
||||||
case KeyNUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyN)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyO:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyO)
|
|
||||||
break
|
|
||||||
case KeyOUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyO)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyP:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyP)
|
|
||||||
break
|
|
||||||
case KeyPUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyP)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyQ:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyQ)
|
|
||||||
break
|
|
||||||
case KeyQUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyQ)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyR:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyR)
|
|
||||||
break
|
|
||||||
case KeyRUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyR)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyS:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyS)
|
|
||||||
break
|
|
||||||
case KeySUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyS)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyT:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyT)
|
|
||||||
break
|
|
||||||
case KeyTUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyT)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyU:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyU)
|
|
||||||
break
|
|
||||||
case KeyUUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyU)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyV:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyV)
|
|
||||||
break
|
|
||||||
case KeyVUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyV)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyW:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyW)
|
|
||||||
break
|
|
||||||
case KeyWUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyW)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyX:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyX)
|
|
||||||
break
|
|
||||||
case KeyXUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyX)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyY:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyY)
|
|
||||||
break
|
|
||||||
case KeyYUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyY)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case KeyZ:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyZ)
|
|
||||||
break
|
|
||||||
case KeyZUpper:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeyZ)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
case Key1:
|
|
||||||
err = keyboard.KeyPress(uinput.Key1)
|
|
||||||
break
|
|
||||||
case Key2:
|
|
||||||
err = keyboard.KeyPress(uinput.Key2)
|
|
||||||
break
|
|
||||||
case Key3:
|
|
||||||
err = keyboard.KeyPress(uinput.Key3)
|
|
||||||
break
|
|
||||||
case Key4:
|
|
||||||
err = keyboard.KeyPress(uinput.Key4)
|
|
||||||
break
|
|
||||||
case Key5:
|
|
||||||
err = keyboard.KeyPress(uinput.Key5)
|
|
||||||
break
|
|
||||||
case Key6:
|
|
||||||
err = keyboard.KeyPress(uinput.Key6)
|
|
||||||
break
|
|
||||||
case Key7:
|
|
||||||
err = keyboard.KeyPress(uinput.Key7)
|
|
||||||
break
|
|
||||||
case Key8:
|
|
||||||
err = keyboard.KeyPress(uinput.Key8)
|
|
||||||
break
|
|
||||||
case Key9:
|
|
||||||
err = keyboard.KeyPress(uinput.Key9)
|
|
||||||
break
|
|
||||||
case Key0:
|
|
||||||
err = keyboard.KeyPress(uinput.Key0)
|
|
||||||
break
|
|
||||||
case KeyTab:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyTab)
|
|
||||||
break
|
|
||||||
case KeyHyphen:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyMinus)
|
|
||||||
break
|
|
||||||
case KeyExclamationMark:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key1)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyAtSign:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key2)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyHash:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key3)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyDollar:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key4)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyPercent:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key5)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyCaret:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key6)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyAmpersand:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key7)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyAsterisk:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.Key8)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeyDot:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyDot)
|
|
||||||
break
|
|
||||||
case KeyComma:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyW)
|
|
||||||
break
|
|
||||||
case KeyQuestionMark:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeySlash)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeySemicolon:
|
|
||||||
err = keyboard.KeyPress(uinput.KeySemicolon)
|
|
||||||
break
|
|
||||||
case KeyColon:
|
|
||||||
err = keyboard.KeyDown(uinput.KeyLeftshift)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyPress(uinput.KeySemicolon)
|
|
||||||
Sleep()
|
|
||||||
err = keyboard.KeyUp(uinput.KeyLeftshift)
|
|
||||||
break
|
|
||||||
case KeySlash:
|
|
||||||
err = keyboard.KeyPress(uinput.KeySlash)
|
|
||||||
break
|
|
||||||
case KeyApostrophe:
|
|
||||||
err = keyboard.KeyPress(uinput.KeyApostrophe)
|
|
||||||
break
|
|
||||||
|
|
||||||
case KeySpace:
|
|
||||||
err = keyboard.KeyPress(uinput.KeySpace)
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
fmt.Println("Unknown key: ", key)
|
|
||||||
fmt.Println("Please add it to the QWERTY layout")
|
|
||||||
return errors.New("Unknown key")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
DefaultLayoutRegistry.Register("qwerty", Qwerty{})
|
|
||||||
}
|
|
|
@ -1,175 +0,0 @@
|
||||||
package uinput
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/bendahl/uinput"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Layout interface {
|
|
||||||
TypeKey(key Key, keyboard uinput.Keyboard) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Key string
|
|
||||||
|
|
||||||
const (
|
|
||||||
KeyA Key = "a"
|
|
||||||
KeyB Key = "b"
|
|
||||||
KeyC Key = "c"
|
|
||||||
KeyD Key = "d"
|
|
||||||
KeyE Key = "e"
|
|
||||||
KeyF Key = "f"
|
|
||||||
KeyG Key = "g"
|
|
||||||
KeyH Key = "h"
|
|
||||||
KeyI Key = "i"
|
|
||||||
KeyJ Key = "j"
|
|
||||||
KeyK Key = "k"
|
|
||||||
KeyL Key = "l"
|
|
||||||
KeyM Key = "m"
|
|
||||||
KeyN Key = "n"
|
|
||||||
KeyO Key = "o"
|
|
||||||
KeyP Key = "p"
|
|
||||||
KeyQ Key = "q"
|
|
||||||
KeyR Key = "r"
|
|
||||||
KeyS Key = "s"
|
|
||||||
KeyT Key = "t"
|
|
||||||
KeyU Key = "u"
|
|
||||||
KeyV Key = "v"
|
|
||||||
KeyW Key = "w"
|
|
||||||
KeyX Key = "x"
|
|
||||||
KeyY Key = "y"
|
|
||||||
KeyZ Key = "z"
|
|
||||||
KeyAUpper Key = "A"
|
|
||||||
KeyBUpper Key = "B"
|
|
||||||
KeyCUpper Key = "C"
|
|
||||||
KeyDUpper Key = "D"
|
|
||||||
KeyEUpper Key = "E"
|
|
||||||
KeyFUpper Key = "F"
|
|
||||||
KeyGUpper Key = "G"
|
|
||||||
KeyHUpper Key = "H"
|
|
||||||
KeyIUpper Key = "I"
|
|
||||||
KeyJUpper Key = "J"
|
|
||||||
KeyKUpper Key = "K"
|
|
||||||
KeyLUpper Key = "L"
|
|
||||||
KeyMUpper Key = "M"
|
|
||||||
KeyNUpper Key = "N"
|
|
||||||
KeyOUpper Key = "O"
|
|
||||||
KeyPUpper Key = "P"
|
|
||||||
KeyQUpper Key = "Q"
|
|
||||||
KeyRUpper Key = "R"
|
|
||||||
KeySUpper Key = "S"
|
|
||||||
KeyTUpper Key = "T"
|
|
||||||
KeyUUpper Key = "U"
|
|
||||||
KeyVUpper Key = "V"
|
|
||||||
KeyWUpper Key = "W"
|
|
||||||
KeyXUpper Key = "X"
|
|
||||||
KeyYUpper Key = "Y"
|
|
||||||
KeyZUpper Key = "Z"
|
|
||||||
Key0 Key = "0"
|
|
||||||
Key1 Key = "1"
|
|
||||||
Key2 Key = "2"
|
|
||||||
Key3 Key = "3"
|
|
||||||
Key4 Key = "4"
|
|
||||||
Key5 Key = "5"
|
|
||||||
Key6 Key = "6"
|
|
||||||
Key7 Key = "7"
|
|
||||||
Key8 Key = "8"
|
|
||||||
Key9 Key = "9"
|
|
||||||
|
|
||||||
KeyHyphen Key = "-"
|
|
||||||
|
|
||||||
KeySpace Key = " "
|
|
||||||
KeyExclamationMark Key = "!"
|
|
||||||
KeyAtSign Key = "@"
|
|
||||||
KeyHash Key = "#"
|
|
||||||
KeyDollar Key = "$"
|
|
||||||
KeyPercent Key = "%"
|
|
||||||
KeyCaret Key = "^"
|
|
||||||
KeyAmpersand Key = "&"
|
|
||||||
KeyAsterisk Key = "*"
|
|
||||||
|
|
||||||
KeyDot Key = "."
|
|
||||||
KeyComma Key = ","
|
|
||||||
KeySlash Key = "/"
|
|
||||||
KeyBackslash Key = "\\"
|
|
||||||
KeyQuestionMark Key = "?"
|
|
||||||
KeySemicolon Key = ";"
|
|
||||||
KeyColon Key = ":"
|
|
||||||
KeyApostrophe Key = "'"
|
|
||||||
|
|
||||||
KeyTab Key = "\t"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LayoutRegistry struct {
|
|
||||||
layouts map[string]Layout
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLayoutRegistry() *LayoutRegistry {
|
|
||||||
return &LayoutRegistry{
|
|
||||||
layouts: make(map[string]Layout),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var DefaultLayoutRegistry = NewLayoutRegistry()
|
|
||||||
|
|
||||||
func (r *LayoutRegistry) Register(name string, layout Layout) {
|
|
||||||
r.layouts[name] = layout
|
|
||||||
}
|
|
||||||
|
|
||||||
func TypeString(text string, layout string) error {
|
|
||||||
if layout == "" {
|
|
||||||
layout = "qwerty"
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := DefaultLayoutRegistry.layouts[layout]; !ok {
|
|
||||||
return errors.New("layout not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
keyboard, err := uinput.CreateKeyboard("/dev/uinput", []byte("testkeyboard"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range text {
|
|
||||||
key := Key(string(c))
|
|
||||||
err := DefaultLayoutRegistry.layouts[layout].TypeKey(key, keyboard)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = keyboard.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Paste(layout string) error {
|
|
||||||
if layout == "" {
|
|
||||||
layout = "qwerty"
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := DefaultLayoutRegistry.layouts[layout]; !ok {
|
|
||||||
return errors.New("layout not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
keyboard, err := uinput.CreateKeyboard("/dev/uinput", []byte("Goldwarden Autotype"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
keyboard.KeyDown(uinput.KeyLeftctrl)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
DefaultLayoutRegistry.layouts[layout].TypeKey(KeyV, keyboard)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
keyboard.KeyUp(uinput.KeyLeftctrl)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Sleep() {
|
|
||||||
time.Sleep(20 * time.Millisecond)
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
//go:build linux && uinput
|
|
||||||
|
|
||||||
package autotype
|
|
||||||
|
|
||||||
import "github.com/quexten/goldwarden/autofill/autotype/uinput"
|
|
||||||
|
|
||||||
func TypeString(text string, layout string) error {
|
|
||||||
return uinput.TypeString(text, layout)
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
//go:build !linux
|
|
||||||
|
|
||||||
package autotype
|
|
||||||
|
|
||||||
func TypeString(text string, layout string) error {
|
|
||||||
return errors.New("Not implemented")
|
|
||||||
}
|
|
|
@ -1,336 +0,0 @@
|
||||||
//go:build !noautofill
|
|
||||||
|
|
||||||
package autofill
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
"log"
|
|
||||||
"math"
|
|
||||||
"os"
|
|
||||||
"os/user"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"gioui.org/app"
|
|
||||||
"gioui.org/font/gofont"
|
|
||||||
"gioui.org/io/key"
|
|
||||||
"gioui.org/io/system"
|
|
||||||
"gioui.org/layout"
|
|
||||||
"gioui.org/op"
|
|
||||||
"gioui.org/op/clip"
|
|
||||||
"gioui.org/op/paint"
|
|
||||||
"gioui.org/unit"
|
|
||||||
"gioui.org/widget"
|
|
||||||
"gioui.org/widget/material"
|
|
||||||
"github.com/shirou/gopsutil/v3/process"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AutofillEntry struct {
|
|
||||||
Username string
|
|
||||||
Name string
|
|
||||||
UUID string
|
|
||||||
}
|
|
||||||
|
|
||||||
var autofillEntries = []AutofillEntry{}
|
|
||||||
var onAutofill func(string, chan bool)
|
|
||||||
var selectedEntry = 0
|
|
||||||
|
|
||||||
type scoredAutofillEntry struct {
|
|
||||||
autofillEntry AutofillEntry
|
|
||||||
score int
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUserProcs() []string {
|
|
||||||
procNames := []string{}
|
|
||||||
|
|
||||||
procs, err := process.Processes()
|
|
||||||
if err != nil {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
for _, proc := range procs {
|
|
||||||
user, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
procuser, err := proc.Username()
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if procuser == user.Username {
|
|
||||||
procName, err := proc.Name()
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
procNames = append(procNames, strings.ToLower(procName))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return procNames
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetFilteredAutofillEntries(entries []AutofillEntry, filter string) []AutofillEntry {
|
|
||||||
if len(filter) == 0 {
|
|
||||||
return []AutofillEntry{}
|
|
||||||
}
|
|
||||||
|
|
||||||
filter = strings.ToLower(filter)
|
|
||||||
|
|
||||||
// filter entrien by whether they contain the filter string
|
|
||||||
filteredEntries := []AutofillEntry{}
|
|
||||||
for _, entry := range entries {
|
|
||||||
name := strings.ToLower(entry.Name)
|
|
||||||
if strings.HasPrefix(name, filter) {
|
|
||||||
filteredEntries = append(filteredEntries, entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processes := getUserProcs()
|
|
||||||
|
|
||||||
scoredEntries := []scoredAutofillEntry{}
|
|
||||||
for _, entry := range filteredEntries {
|
|
||||||
score := 0
|
|
||||||
name := strings.ToLower(entry.Name)
|
|
||||||
filter = strings.ToLower(filter)
|
|
||||||
|
|
||||||
maxProcessScore := 0
|
|
||||||
|
|
||||||
for _, process := range processes {
|
|
||||||
score := 0
|
|
||||||
|
|
||||||
sharedPrefixLen := 0
|
|
||||||
for i := 0; i < len(process) && i < len(entry.Name); i++ {
|
|
||||||
if process[i] == name[i] {
|
|
||||||
sharedPrefixLen++
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sharedPrefixLenPercent := float32(sharedPrefixLen) / float32(math.Min(float64(len(process)), float64(len(name))))
|
|
||||||
|
|
||||||
if sharedPrefixLen > 0 {
|
|
||||||
score += int(sharedPrefixLenPercent * 7)
|
|
||||||
}
|
|
||||||
|
|
||||||
if score > maxProcessScore {
|
|
||||||
maxProcessScore = score
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
score += maxProcessScore
|
|
||||||
scoredEntries = append(scoredEntries, scoredAutofillEntry{entry, score})
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(scoredEntries, func(i, j int) bool {
|
|
||||||
return scoredEntries[i].score > scoredEntries[j].score
|
|
||||||
})
|
|
||||||
|
|
||||||
var filteredEntries1 []AutofillEntry
|
|
||||||
for _, scoredEntry := range scoredEntries {
|
|
||||||
if scoredEntry.score == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
filteredEntries1 = append(filteredEntries1, scoredEntry.autofillEntry)
|
|
||||||
}
|
|
||||||
|
|
||||||
return filteredEntries1
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunAutofill(entries []AutofillEntry, onAutofillFunc func(string, chan bool)) {
|
|
||||||
autofillEntries = entries
|
|
||||||
onAutofill = onAutofillFunc
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
w := app.NewWindow()
|
|
||||||
w.Option(app.Size(unit.Dp(600), unit.Dp(800)))
|
|
||||||
w.Option(app.Decorated(false))
|
|
||||||
w.Perform(system.ActionCenter)
|
|
||||||
w.Perform(system.ActionRaise)
|
|
||||||
lineEditor.Focus()
|
|
||||||
if err := loop(w); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
app.Main()
|
|
||||||
}
|
|
||||||
|
|
||||||
var lineEditor = &widget.Editor{
|
|
||||||
SingleLine: true,
|
|
||||||
Submit: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
unselected = color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xFF}
|
|
||||||
unselectedText = color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF}
|
|
||||||
background = color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xFF}
|
|
||||||
selected = color.NRGBA{R: 0x65, G: 0x1F, B: 0xFF, A: 0xFF}
|
|
||||||
selectedText = color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF}
|
|
||||||
)
|
|
||||||
|
|
||||||
var th = material.NewTheme(gofont.Collection())
|
|
||||||
var list = layout.List{Axis: layout.Vertical}
|
|
||||||
|
|
||||||
func doLayout(gtx layout.Context) layout.Dimensions {
|
|
||||||
var filteredEntries []AutofillEntry = GetFilteredAutofillEntries(autofillEntries, lineEditor.Text())
|
|
||||||
|
|
||||||
if selectedEntry >= 10 || selectedEntry >= len(filteredEntries) {
|
|
||||||
selectedEntry = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return Background{Color: background, CornerRadius: unit.Dp(0)}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
|
||||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
return Background{Color: background, CornerRadius: unit.Dp(0)}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
|
||||||
return layout.UniformInset(unit.Dp(10)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
|
||||||
searchBox := material.Editor(th, lineEditor, "Search query")
|
|
||||||
searchBox.Color = selectedText
|
|
||||||
border := widget.Border{Color: selectedText, CornerRadius: unit.Dp(8), Width: unit.Dp(2)}
|
|
||||||
return border.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
|
||||||
return layout.UniformInset(unit.Dp(8)).Layout(gtx, searchBox.Layout)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
return layout.UniformInset(unit.Dp(10)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
|
||||||
|
|
||||||
return list.Layout(gtx, len(filteredEntries), func(gtx layout.Context, i int) layout.Dimensions {
|
|
||||||
entry := filteredEntries[i]
|
|
||||||
|
|
||||||
return layout.Inset{Bottom: unit.Dp(10)}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
|
||||||
isSelected := i == selectedEntry
|
|
||||||
var color color.NRGBA
|
|
||||||
if isSelected {
|
|
||||||
color = selected
|
|
||||||
} else {
|
|
||||||
color = unselected
|
|
||||||
}
|
|
||||||
|
|
||||||
return Background{Color: color, CornerRadius: unit.Dp(8)}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
|
||||||
return layout.UniformInset(unit.Dp(10)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
|
||||||
dimens := layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
t := material.H6(th, entry.Name)
|
|
||||||
if isSelected {
|
|
||||||
t.Color = selectedText
|
|
||||||
} else {
|
|
||||||
t.Color = unselectedText
|
|
||||||
}
|
|
||||||
return t.Layout(gtx)
|
|
||||||
}),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
t := material.Body1(th, entry.Username)
|
|
||||||
if isSelected {
|
|
||||||
t.Color = selectedText
|
|
||||||
} else {
|
|
||||||
t.Color = unselectedText
|
|
||||||
}
|
|
||||||
|
|
||||||
return t.Layout(gtx)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
return dimens
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func loop(w *app.Window) error {
|
|
||||||
var ops op.Ops
|
|
||||||
for {
|
|
||||||
e := <-w.Events()
|
|
||||||
switch e := e.(type) {
|
|
||||||
case system.DestroyEvent:
|
|
||||||
return e.Err
|
|
||||||
case system.FrameEvent:
|
|
||||||
gtx := layout.NewContext(&ops, e)
|
|
||||||
|
|
||||||
key.InputOp{
|
|
||||||
Keys: key.Set(key.NameReturn + "|" + key.NameEscape + "|" + key.NameDownArrow),
|
|
||||||
Tag: 0,
|
|
||||||
}.Add(gtx.Ops)
|
|
||||||
t := lineEditor.Events()
|
|
||||||
for _, ev := range t {
|
|
||||||
switch ev.(type) {
|
|
||||||
case widget.SubmitEvent:
|
|
||||||
entries := GetFilteredAutofillEntries(autofillEntries, lineEditor.Text())
|
|
||||||
if len(entries) == 0 {
|
|
||||||
fmt.Println("no entries")
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
w.Perform(system.ActionMinimize)
|
|
||||||
c := make(chan bool)
|
|
||||||
go onAutofill(entries[selectedEntry].UUID, c)
|
|
||||||
go func() {
|
|
||||||
<-c
|
|
||||||
os.Exit(0)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test := gtx.Events(0)
|
|
||||||
for _, ev := range test {
|
|
||||||
switch ev := ev.(type) {
|
|
||||||
case key.Event:
|
|
||||||
switch ev.Name {
|
|
||||||
case key.NameReturn:
|
|
||||||
fmt.Println("uncaught submit")
|
|
||||||
return nil
|
|
||||||
case key.NameDownArrow:
|
|
||||||
if ev.State == key.Press {
|
|
||||||
selectedEntry++
|
|
||||||
if selectedEntry >= 10 {
|
|
||||||
selectedEntry = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case key.NameEscape:
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
doLayout(gtx)
|
|
||||||
e.Frame(gtx.Ops)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Background struct {
|
|
||||||
Color color.NRGBA
|
|
||||||
CornerRadius unit.Dp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b Background) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions {
|
|
||||||
m := op.Record(gtx.Ops)
|
|
||||||
dims := w(gtx)
|
|
||||||
size := dims.Size
|
|
||||||
call := m.Stop()
|
|
||||||
if r := gtx.Dp(b.CornerRadius); r > 0 {
|
|
||||||
defer clip.RRect{
|
|
||||||
Rect: image.Rect(0, 0, size.X, size.Y),
|
|
||||||
NE: r, NW: r, SE: r, SW: r,
|
|
||||||
}.Push(gtx.Ops).Pop()
|
|
||||||
}
|
|
||||||
fill{b.Color}.Layout(gtx, size)
|
|
||||||
call.Add(gtx.Ops)
|
|
||||||
return dims
|
|
||||||
}
|
|
||||||
|
|
||||||
type fill struct {
|
|
||||||
col color.NRGBA
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f fill) Layout(gtx layout.Context, sz image.Point) layout.Dimensions {
|
|
||||||
defer clip.Rect(image.Rectangle{Max: sz}).Push(gtx.Ops).Pop()
|
|
||||||
paint.ColorOp{Color: f.col}.Add(gtx.Ops)
|
|
||||||
paint.PaintOp{}.Add(gtx.Ops)
|
|
||||||
return layout.Dimensions{Size: sz}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build linux && !uinput
|
//go:build linux
|
||||||
|
|
||||||
package autotype
|
package autotype
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ var globalID = 0
|
||||||
|
|
||||||
const autoTypeDelay = 1 * time.Millisecond
|
const autoTypeDelay = 1 * time.Millisecond
|
||||||
|
|
||||||
func TypeString(textToType string, layout string) {
|
func TypeString(textToType string) {
|
||||||
bus, err := dbus.SessionBus()
|
bus, err := dbus.SessionBus()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
|
@ -1,24 +1,25 @@
|
||||||
//go:build !noautofill
|
//go:build linux
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/quexten/goldwarden/autofill"
|
"github.com/quexten/goldwarden/autotype"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var autofillCmd = &cobra.Command{
|
var autofillCmd = &cobra.Command{
|
||||||
Use: "autofill",
|
Use: "autotype",
|
||||||
Short: "Autofill credentials",
|
Short: "Autotype credentials",
|
||||||
Long: `Autofill credentials`,
|
Long: `Autotype credentials`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
layout := cmd.Flag("layout").Value.String()
|
username, _ := cmd.Flags().GetString("username")
|
||||||
autofill.Run(layout, commandClient)
|
password, _ := cmd.Flags().GetString("password")
|
||||||
|
autotype.TypeString(username + "\t" + password)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(autofillCmd)
|
rootCmd.AddCommand(autofillCmd)
|
||||||
autofillCmd.PersistentFlags().String("layout", "qwerty", "")
|
autofillCmd.PersistentFlags().String("username", "", "")
|
||||||
autofillCmd.PersistentFlags().Bool("use-copy-paste", false, "")
|
autofillCmd.PersistentFlags().String("password", "", "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/icza/gox/stringsx"
|
||||||
|
"github.com/quexten/goldwarden/client"
|
||||||
"github.com/quexten/goldwarden/ipc/messages"
|
"github.com/quexten/goldwarden/ipc/messages"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -54,6 +59,61 @@ var getLoginCmd = &cobra.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var listLoginsCmd = &cobra.Command{
|
||||||
|
Use: "list",
|
||||||
|
Short: "Lists all logins in your vault",
|
||||||
|
Long: `Lists all logins in your vault.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
loginIfRequired()
|
||||||
|
|
||||||
|
logins, err := ListLogins(commandClient)
|
||||||
|
if err != nil {
|
||||||
|
handleSendToAgentError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[")
|
||||||
|
for index, login := range logins {
|
||||||
|
data := map[string]string{
|
||||||
|
"name": stringsx.Clean(login.Name),
|
||||||
|
"uuid": stringsx.Clean(login.UUID),
|
||||||
|
"username": stringsx.Clean(login.Username),
|
||||||
|
"password": stringsx.Clean(strings.ReplaceAll(login.Password, "\"", "\\\"")),
|
||||||
|
}
|
||||||
|
jsonString, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
handleSendToAgentError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Print(string(jsonString))
|
||||||
|
if index != len(logins)-1 {
|
||||||
|
fmt.Println(",")
|
||||||
|
} else {
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("]")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListLogins(client client.Client) ([]messages.DecryptedLoginCipher, error) {
|
||||||
|
resp, err := client.SendToAgent(messages.ListLoginsRequest{})
|
||||||
|
if err != nil {
|
||||||
|
return []messages.DecryptedLoginCipher{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch resp.(type) {
|
||||||
|
case messages.GetLoginsResponse:
|
||||||
|
castedResponse := (resp.(messages.GetLoginsResponse))
|
||||||
|
return castedResponse.Result, nil
|
||||||
|
case messages.ActionResponse:
|
||||||
|
castedResponse := (resp.(messages.ActionResponse))
|
||||||
|
return []messages.DecryptedLoginCipher{}, errors.New("Error: " + castedResponse.Message)
|
||||||
|
default:
|
||||||
|
return []messages.DecryptedLoginCipher{}, errors.New("Wrong response type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(baseLoginCmd)
|
rootCmd.AddCommand(baseLoginCmd)
|
||||||
baseLoginCmd.AddCommand(getLoginCmd)
|
baseLoginCmd.AddCommand(getLoginCmd)
|
||||||
|
@ -61,4 +121,5 @@ func init() {
|
||||||
getLoginCmd.PersistentFlags().String("username", "", "")
|
getLoginCmd.PersistentFlags().String("username", "", "")
|
||||||
getLoginCmd.PersistentFlags().String("uuid", "", "")
|
getLoginCmd.PersistentFlags().String("uuid", "", "")
|
||||||
getLoginCmd.PersistentFlags().Bool("full", false, "")
|
getLoginCmd.PersistentFlags().Bool("full", false, "")
|
||||||
|
baseLoginCmd.AddCommand(listLoginsCmd)
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,9 +107,11 @@ var statusCmd = &cobra.Command{
|
||||||
switch result.(type) {
|
switch result.(type) {
|
||||||
case messages.VaultStatusResponse:
|
case messages.VaultStatusResponse:
|
||||||
status := result.(messages.VaultStatusResponse)
|
status := result.(messages.VaultStatusResponse)
|
||||||
fmt.Println("Locked: ", status.Locked)
|
fmt.Println("{")
|
||||||
fmt.Println("Number of logins: ", status.NumberOfLogins)
|
fmt.Println(" \"locked\":", status.Locked, ",")
|
||||||
fmt.Println("Number of notes: ", status.NumberOfNotes)
|
fmt.Println(" \"loginEntries\":", status.NumberOfLogins, ",")
|
||||||
|
fmt.Println(" \"noteEntries\":", status.NumberOfNotes)
|
||||||
|
fmt.Println("}")
|
||||||
default:
|
default:
|
||||||
println("Wrong response type")
|
println("Wrong response type")
|
||||||
}
|
}
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -30,6 +30,9 @@ 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-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/go-text/typesetting v0.0.0-20230602202114-9797aefac433 // 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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -45,8 +45,14 @@ github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
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.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
|
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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/k0kubun/pp v2.4.0+incompatible h1:M9iQzcejGfiBjDa7+Tc0rJgR7WFKP6rim/Q0DDrAT3g=
|
||||||
|
github.com/k0kubun/pp v2.4.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
|
||||||
|
github.com/k0kubun/pp/v3 v3.2.0 h1:h33hNTZ9nVFNP3u2Fsgz8JXiF5JINoZfFq4SvKJwNcs=
|
||||||
|
github.com/k0kubun/pp/v3 v3.2.0/go.mod h1:ODtJQbQcIRfAD3N+theGCV1m/CBxweERz2dapdz1EwA=
|
||||||
github.com/keys-pub/go-libfido2 v1.5.3 h1:vtgHxlSB43u6lj0TSuA3VvT6z3E7VI+L1a2hvMFdECk=
|
github.com/keys-pub/go-libfido2 v1.5.3 h1:vtgHxlSB43u6lj0TSuA3VvT6z3E7VI+L1a2hvMFdECk=
|
||||||
github.com/keys-pub/go-libfido2 v1.5.3/go.mod h1:P0V19qHwJNY0htZwZDe9Ilvs/nokGhdFX7faKFyZ6+U=
|
github.com/keys-pub/go-libfido2 v1.5.3/go.mod h1:P0V19qHwJNY0htZwZDe9Ilvs/nokGhdFX7faKFyZ6+U=
|
||||||
github.com/lox/go-touchid v0.0.0-20170712105233-619cc8e578d0 h1:m81erW+1MD5vl3lKQ/+TYPHJ6Y9/C1COqxXPE51FkDk=
|
github.com/lox/go-touchid v0.0.0-20170712105233-619cc8e578d0 h1:m81erW+1MD5vl3lKQ/+TYPHJ6Y9/C1COqxXPE51FkDk=
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
# TODO??!?!? for now using golang implementation
|
||||||
|
|
||||||
|
import dbus
|
||||||
|
import dbus.mainloop.glib
|
||||||
|
from dbus.mainloop.glib import DBusGMainLoop
|
||||||
|
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
|
step = 0
|
||||||
|
|
||||||
|
def typestring(text):
|
||||||
|
step = 0
|
||||||
|
handle = ""
|
||||||
|
|
||||||
|
def handler(*args, **kwargs):
|
||||||
|
global step
|
||||||
|
if step == 0:
|
||||||
|
handle_xdp_session_created(*args, **kwargs)
|
||||||
|
elif step == 1:
|
||||||
|
handle_xdp_devices_selected(*args, **kwargs)
|
||||||
|
elif step == 2:
|
||||||
|
handle_session_start(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
print(args, kwargs)
|
||||||
|
step += 1
|
||||||
|
|
||||||
|
def handle_session_start(code, results, object_path):
|
||||||
|
global handle
|
||||||
|
|
||||||
|
if code != 0:
|
||||||
|
raise Exception("Could not start session")
|
||||||
|
|
||||||
|
for sym in text:
|
||||||
|
if sym == "\t":
|
||||||
|
inter.NotifyKeyboardKeycode(handle, {}, 15, 1)
|
||||||
|
time.sleep(0.001)
|
||||||
|
inter.NotifyKeyboardKeycode(handle, {}, 15, 0)
|
||||||
|
time.sleep(0.001)
|
||||||
|
else:
|
||||||
|
inter.NotifyKeyboardKeysym(handle, {}, ord(sym), 1)
|
||||||
|
time.sleep(0.001)
|
||||||
|
inter.NotifyKeyboardKeysym(handle, {}, ord(sym), 0)
|
||||||
|
time.sleep(0.001)
|
||||||
|
|
||||||
|
bus
|
||||||
|
|
||||||
|
def handle_xdp_devices_selected(code, results, object_path):
|
||||||
|
global handle
|
||||||
|
|
||||||
|
if code != 0:
|
||||||
|
raise Exception("Could not select devices")
|
||||||
|
|
||||||
|
start_options = {
|
||||||
|
"handle_token": "krfb" + str(random.randint(0, 999999999))
|
||||||
|
}
|
||||||
|
reply = inter.Start(handle, "", start_options)
|
||||||
|
print(reply)
|
||||||
|
|
||||||
|
def handle_xdp_session_created(code, results, object_path):
|
||||||
|
global handle
|
||||||
|
|
||||||
|
if code != 0:
|
||||||
|
raise Exception("Could not create session")
|
||||||
|
print(results)
|
||||||
|
handle = results["session_handle"]
|
||||||
|
|
||||||
|
# select sources for the session
|
||||||
|
selection_options = {
|
||||||
|
"types": dbus.UInt32(7), # request all (KeyBoard, Pointer, TouchScreen)
|
||||||
|
"handle_token": "krfb" + str(random.randint(0, 999999999))
|
||||||
|
}
|
||||||
|
selector_reply = inter.SelectDevices(handle, selection_options)
|
||||||
|
print(selector_reply)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global bus
|
||||||
|
global inter
|
||||||
|
loop = GLib.MainLoop()
|
||||||
|
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||||
|
bus = dbus.SessionBus()
|
||||||
|
obj = bus.get_object("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop")
|
||||||
|
inter = dbus.Interface(obj, "org.freedesktop.portal.RemoteDesktop")
|
||||||
|
|
||||||
|
bus.add_signal_receiver(
|
||||||
|
handler,
|
||||||
|
signal_name="Response",
|
||||||
|
dbus_interface="org.freedesktop.portal.Request",
|
||||||
|
bus_name="org.freedesktop.portal.Desktop",
|
||||||
|
path_keyword="object_path")
|
||||||
|
|
||||||
|
print(inter)
|
||||||
|
result = inter.CreateSession({
|
||||||
|
"session_handle_token": "sessionhandletoken"
|
||||||
|
})
|
||||||
|
print(result)
|
||||||
|
loop.run()
|
||||||
|
|
||||||
|
main()
|
|
@ -0,0 +1,5 @@
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def write(text):
|
||||||
|
process = subprocess.Popen(["/bin/sh", "-c", "wl-copy"], stdin=subprocess.PIPE)
|
||||||
|
process.communicate(text.encode('utf-8'))
|
|
@ -0,0 +1,87 @@
|
||||||
|
import subprocess
|
||||||
|
import json
|
||||||
|
|
||||||
|
BINARY_PATH = "/home/quexten/go/src/github.com/quexten/goldwarden/goldwarden"
|
||||||
|
|
||||||
|
def set_api_url(url):
|
||||||
|
restic_cmd = f"{BINARY_PATH} config set-api-url {url}"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
|
||||||
|
def set_identity_url(url):
|
||||||
|
restic_cmd = f"{BINARY_PATH} config set-identity-url {url}"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
|
||||||
|
def set_notification_url(url):
|
||||||
|
restic_cmd = f"{BINARY_PATH} config set-notifications-url {url}"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
|
||||||
|
def login_with_password(email, password):
|
||||||
|
restic_cmd = f"{BINARY_PATH} vault login --email {email}"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
if len(result.stderr.strip()) > 0:
|
||||||
|
print(result.stderr)
|
||||||
|
if "password" in result.stderr:
|
||||||
|
return "badpass"
|
||||||
|
else:
|
||||||
|
if "Logged in" in result.stderr:
|
||||||
|
print("ok")
|
||||||
|
return "ok"
|
||||||
|
return "error"
|
||||||
|
print("ok")
|
||||||
|
return "ok"
|
||||||
|
|
||||||
|
def login_passwordless(email):
|
||||||
|
restic_cmd = f"{BINARY_PATH} vault login --email {email} --passwordless"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
|
||||||
|
def is_pin_enabled():
|
||||||
|
restic_cmd = f"{BINARY_PATH} vault pin"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
# check if contains enabled
|
||||||
|
return "enabled" in result.stdout
|
||||||
|
|
||||||
|
def enable_pin():
|
||||||
|
restic_cmd = f"{BINARY_PATH} vault pin set"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
|
||||||
|
def get_vault_status():
|
||||||
|
restic_cmd = f"{BINARY_PATH} vault status"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
try:
|
||||||
|
return json.loads(result.stdout)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_vault_logins():
|
||||||
|
restic_cmd = f"{BINARY_PATH} logins list"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
||||||
|
try:
|
||||||
|
return json.loads(result.stdout)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def autotype(username, password):
|
||||||
|
restic_cmd = f"{BINARY_PATH} autotype --username {username} --password {password}"
|
||||||
|
result = subprocess.run(restic_cmd.split(), capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception("Failed to initialize repository, err", result.stderr)
|
|
@ -0,0 +1,286 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import sys
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '4.0')
|
||||||
|
gi.require_version('Adw', '1')
|
||||||
|
import gc
|
||||||
|
|
||||||
|
from gi.repository import Gtk, Adw, Gdk, Graphene, Gsk, Gio, GLib, GObject
|
||||||
|
import monitors.dbus_autofill_monitor
|
||||||
|
import goldwarden
|
||||||
|
import clipboard
|
||||||
|
import time
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
class MainWindow(Gtk.ApplicationWindow):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.stack = Gtk.Stack()
|
||||||
|
self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
|
||||||
|
self.set_child(self.stack)
|
||||||
|
|
||||||
|
self.box = Gtk.Box()
|
||||||
|
self.box.set_orientation(Gtk.Orientation.VERTICAL)
|
||||||
|
self.stack.add_named(self.box, "box")
|
||||||
|
|
||||||
|
|
||||||
|
self.text_view = Adw.EntryRow()
|
||||||
|
self.text_view.set_title("Search")
|
||||||
|
# on type func
|
||||||
|
def on_type(entry):
|
||||||
|
if len(entry.get_text()) > 1:
|
||||||
|
self.history_list.show()
|
||||||
|
else:
|
||||||
|
self.history_list.hide()
|
||||||
|
|
||||||
|
while self.history_list.get_first_child() != None:
|
||||||
|
self.history_list.remove(self.history_list.get_first_child())
|
||||||
|
|
||||||
|
self.filtered_logins = list(filter(lambda i: entry.get_text().lower() in i["name"].lower(), self.logins))
|
||||||
|
if len( self.filtered_logins) > 10:
|
||||||
|
self.filtered_logins = self.filtered_logins[0:10]
|
||||||
|
self.starts_with_logins = list(filter(lambda i: i["name"].lower().startswith(entry.get_text().lower()), self.logins))
|
||||||
|
self.other_logins = list(filter(lambda i: i not in self.starts_with_logins , self.filtered_logins))
|
||||||
|
self.filtered_logins = None
|
||||||
|
|
||||||
|
for i in self.starts_with_logins + self.other_logins :
|
||||||
|
action_row = Adw.ActionRow()
|
||||||
|
action_row.set_title(i["name"])
|
||||||
|
action_row.set_subtitle(i["username"])
|
||||||
|
action_row.set_icon_name("dialog-password")
|
||||||
|
action_row.set_activatable(True)
|
||||||
|
action_row.password = i["password"]
|
||||||
|
action_row.username = i["username"]
|
||||||
|
self.history_list.append(action_row)
|
||||||
|
self.starts_with_logins = None
|
||||||
|
self.other_logins = None
|
||||||
|
self.text_view.connect("changed", lambda entry: on_type(entry))
|
||||||
|
self.box.append(self.text_view)
|
||||||
|
|
||||||
|
self.history_list = Gtk.ListBox()
|
||||||
|
# margin'
|
||||||
|
self.history_list.set_margin_start(10)
|
||||||
|
self.history_list.set_margin_end(10)
|
||||||
|
self.history_list.set_margin_top(10)
|
||||||
|
self.history_list.set_margin_bottom(10)
|
||||||
|
self.history_list.hide()
|
||||||
|
|
||||||
|
keycont = Gtk.EventControllerKey()
|
||||||
|
def handle_keypress(controller, keyval, keycode, state, user_data):
|
||||||
|
if keycode == 36:
|
||||||
|
print("enter")
|
||||||
|
self.hide()
|
||||||
|
def do_autotype(username, password):
|
||||||
|
time.sleep(0.5)
|
||||||
|
goldwarden.autotype(username, password)
|
||||||
|
GLib.idle_add(lambda: self.show())
|
||||||
|
autotypeThread = Thread(target=do_autotype, args=(self.history_list.get_selected_row().username, self.history_list.get_selected_row().password,))
|
||||||
|
autotypeThread.start()
|
||||||
|
print(self.history_list.get_selected_row().get_title())
|
||||||
|
if keyval == 112:
|
||||||
|
print("copy password")
|
||||||
|
clipboard.write(self.history_list.get_selected_row().password)
|
||||||
|
elif keyval == 117:
|
||||||
|
print("copy username")
|
||||||
|
clipboard.write(self.history_list.get_selected_row().username)
|
||||||
|
|
||||||
|
keycont.connect('key-pressed', handle_keypress, self)
|
||||||
|
self.add_controller(keycont)
|
||||||
|
|
||||||
|
self.history_list.get_style_context().add_class("boxed-list")
|
||||||
|
self.box.append(self.history_list)
|
||||||
|
self.set_default_size(700, 700)
|
||||||
|
self.set_title("Goldwarden")
|
||||||
|
|
||||||
|
def on_close(window):
|
||||||
|
while self.history_list.get_first_child() != None:
|
||||||
|
self.history_list.remove(self.history_list.get_first_child())
|
||||||
|
window.hide()
|
||||||
|
gc.collect()
|
||||||
|
return True
|
||||||
|
self.connect("close-request", on_close)
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
for i in range(0, 5):
|
||||||
|
action_row = Adw.ActionRow()
|
||||||
|
action_row.set_title("aaa")
|
||||||
|
action_row.set_subtitle("Test")
|
||||||
|
self.history_list.append(action_row)
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsWinvdow(Gtk.ApplicationWindow):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.stack = Gtk.Stack()
|
||||||
|
self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
|
||||||
|
self.set_child(self.stack)
|
||||||
|
|
||||||
|
self.preferences_page = Adw.PreferencesPage()
|
||||||
|
self.preferences_page.set_title("General")
|
||||||
|
self.stack.add_named(self.preferences_page, "preferences_page")
|
||||||
|
|
||||||
|
self.preferences_group = Adw.PreferencesGroup()
|
||||||
|
self.preferences_group.set_title("Services")
|
||||||
|
self.preferences_page.add(self.preferences_group)
|
||||||
|
|
||||||
|
self.ssh_row = Adw.ActionRow()
|
||||||
|
self.ssh_row.set_title("SSH Daemon")
|
||||||
|
self.ssh_row.set_subtitle("Listening at ~/.goldwarden-ssh-agent.sock")
|
||||||
|
self.preferences_group.add(self.ssh_row)
|
||||||
|
|
||||||
|
self.login_with_device = Adw.ActionRow()
|
||||||
|
self.login_with_device.set_title("Login with device")
|
||||||
|
self.login_with_device.set_subtitle("Waiting for requests...")
|
||||||
|
self.preferences_group.add(self.login_with_device)
|
||||||
|
|
||||||
|
self.autofill_row = Adw.ActionRow()
|
||||||
|
self.autofill_row.set_title("Autofill Shortcut")
|
||||||
|
self.autofill_row.set_subtitle("Unavailable")
|
||||||
|
self.preferences_group.add(self.autofill_row)
|
||||||
|
|
||||||
|
self.status_row = Adw.ActionRow()
|
||||||
|
self.status_row.set_title("DBUS Service")
|
||||||
|
self.status_row.set_subtitle("Listening")
|
||||||
|
self.preferences_group.add(self.status_row)
|
||||||
|
|
||||||
|
self.status_row = Adw.ActionRow()
|
||||||
|
self.status_row.set_title("Vault Status")
|
||||||
|
self.status_row.set_subtitle("Locked")
|
||||||
|
self.preferences_group.add(self.status_row)
|
||||||
|
|
||||||
|
self.login_row = Adw.ActionRow()
|
||||||
|
self.login_row.set_title("Vault Login Entries")
|
||||||
|
self.login_row.set_subtitle("0")
|
||||||
|
self.preferences_group.add(self.login_row)
|
||||||
|
|
||||||
|
self.notes_row = Adw.ActionRow()
|
||||||
|
self.notes_row.set_title("Vault Notes")
|
||||||
|
self.notes_row.set_subtitle("0")
|
||||||
|
self.preferences_group.add(self.notes_row)
|
||||||
|
|
||||||
|
self.login_button = Gtk.Button()
|
||||||
|
self.login_button.set_label("Login")
|
||||||
|
self.login_button.connect("clicked", lambda button: show_login())
|
||||||
|
self.login_button.set_margin_top(10)
|
||||||
|
self.preferences_group.add(self.login_button)
|
||||||
|
|
||||||
|
self.set_pin_button = Gtk.Button()
|
||||||
|
self.set_pin_button.set_label("Set Pin")
|
||||||
|
def set_pin():
|
||||||
|
set_pin_thread = Thread(target=goldwarden.enable_pin)
|
||||||
|
set_pin_thread.start()
|
||||||
|
self.set_pin_button.connect("clicked", lambda button: set_pin())
|
||||||
|
self.set_pin_button.set_margin_top(10)
|
||||||
|
self.preferences_group.add(self.set_pin_button)
|
||||||
|
|
||||||
|
self.unlock_button = Gtk.Button()
|
||||||
|
self.unlock_button.set_label("Unlock")
|
||||||
|
self.unlock_button.set_margin_top(10)
|
||||||
|
self.preferences_group.add(self.unlock_button)
|
||||||
|
|
||||||
|
def update_labels():
|
||||||
|
status = goldwarden.get_vault_status()
|
||||||
|
self.status_row.set_subtitle(str("Unlocked" if status["locked"] == False else "Locked"))
|
||||||
|
self.login_row.set_subtitle(str(status["loginEntries"]))
|
||||||
|
self.notes_row.set_subtitle(str(status["noteEntries"]))
|
||||||
|
GLib.timeout_add(1000, update_labels)
|
||||||
|
|
||||||
|
GLib.timeout_add(1000, update_labels)
|
||||||
|
self.set_default_size(400, 700)
|
||||||
|
self.set_title("Goldwarden")
|
||||||
|
|
||||||
|
|
||||||
|
#add title buttons
|
||||||
|
self.title_bar = Gtk.HeaderBar()
|
||||||
|
self.set_titlebar(self.title_bar)
|
||||||
|
|
||||||
|
class MyApp(Adw.Application):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.connect('activate', self.on_activate)
|
||||||
|
|
||||||
|
def on_activate(self, app):
|
||||||
|
if hasattr(self, "win") is False:
|
||||||
|
app.hold()
|
||||||
|
self.win = MainWindow(application=app)
|
||||||
|
self.win.set_hide_on_close(True)
|
||||||
|
self.win.hide()
|
||||||
|
self.settings_win = SettingsWinvdow(application=app)
|
||||||
|
self.settings_win.set_hide_on_close(True)
|
||||||
|
self.settings_win.present()
|
||||||
|
|
||||||
|
app = MyApp(application_id="com.quexten.Goldwarden")
|
||||||
|
def on_autofill():
|
||||||
|
logins = goldwarden.get_vault_logins()
|
||||||
|
if logins == None:
|
||||||
|
return
|
||||||
|
app.win.logins = logins
|
||||||
|
app.win.show()
|
||||||
|
app.win.present()
|
||||||
|
monitors.dbus_autofill_monitor.on_autofill = on_autofill
|
||||||
|
|
||||||
|
def show_login():
|
||||||
|
dialog = Gtk.Dialog(title="Goldwarden")
|
||||||
|
preference_group = Adw.PreferencesGroup()
|
||||||
|
preference_group.set_title("Config")
|
||||||
|
dialog.get_content_area().append(preference_group)
|
||||||
|
|
||||||
|
api_url_entry = Adw.EntryRow()
|
||||||
|
api_url_entry.set_title("API Url")
|
||||||
|
# set value
|
||||||
|
api_url_entry.set_text("https://api.bitwarden.com/")
|
||||||
|
preference_group.add(api_url_entry)
|
||||||
|
|
||||||
|
identity_url_entry = Adw.EntryRow()
|
||||||
|
identity_url_entry.set_title("Identity Url")
|
||||||
|
identity_url_entry.set_text("https://identity.bitwarden.com/")
|
||||||
|
preference_group.add(identity_url_entry)
|
||||||
|
|
||||||
|
notification_url_entry = Adw.EntryRow()
|
||||||
|
notification_url_entry.set_title("Notification URL")
|
||||||
|
notification_url_entry.set_text("https://notifications.bitwarden.com/")
|
||||||
|
preference_group.add(notification_url_entry)
|
||||||
|
|
||||||
|
auth_preference_group = Adw.PreferencesGroup()
|
||||||
|
auth_preference_group.set_title("Authentication")
|
||||||
|
dialog.get_content_area().append(auth_preference_group)
|
||||||
|
|
||||||
|
email_entry = Adw.EntryRow()
|
||||||
|
email_entry.set_title("Email")
|
||||||
|
email_entry.set_text("")
|
||||||
|
auth_preference_group.add(email_entry)
|
||||||
|
|
||||||
|
dialog.add_button("Login", Gtk.ResponseType.OK)
|
||||||
|
def on_save(res):
|
||||||
|
if res != Gtk.ResponseType.OK:
|
||||||
|
return
|
||||||
|
goldwarden.set_api_url(api_url_entry.get_text())
|
||||||
|
goldwarden.set_identity_url(identity_url_entry.get_text())
|
||||||
|
goldwarden.set_notification_url(notification_url_entry.get_text())
|
||||||
|
def login():
|
||||||
|
res = goldwarden.login_with_password(email_entry.get_text(), "password")
|
||||||
|
def handle_res():
|
||||||
|
print("handle res", res)
|
||||||
|
if res == "ok":
|
||||||
|
dialog.close()
|
||||||
|
print("ok")
|
||||||
|
elif res == "badpass":
|
||||||
|
bad_pass_diag = Gtk.MessageDialog(transient_for=dialog, modal=True, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, text="Bad password")
|
||||||
|
bad_pass_diag.connect("response", lambda dialog, response: bad_pass_diag.close())
|
||||||
|
bad_pass_diag.present()
|
||||||
|
GLib.idle_add(handle_res)
|
||||||
|
|
||||||
|
login_thread = Thread(target=login)
|
||||||
|
login_thread.start()
|
||||||
|
|
||||||
|
#ok response
|
||||||
|
dialog.connect("response", lambda dialog, response: on_save(response))
|
||||||
|
dialog.set_default_size(400, 200)
|
||||||
|
dialog.set_modal(True)
|
||||||
|
dialog.present()
|
||||||
|
|
||||||
|
|
||||||
|
app.run(sys.argv)
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#Python DBUS Test Server
|
||||||
|
#runs until the Quit() method is called via DBUS
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
import dbus
|
||||||
|
import dbus.service
|
||||||
|
from dbus.mainloop.glib import DBusGMainLoop
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
on_autofill = lambda: None
|
||||||
|
|
||||||
|
class GoldwardenDBUSService(dbus.service.Object):
|
||||||
|
def __init__(self):
|
||||||
|
bus_name = dbus.service.BusName('com.quexten.goldwarden', bus=dbus.SessionBus())
|
||||||
|
dbus.service.Object.__init__(self, bus_name, '/com/quexten/goldwarden')
|
||||||
|
|
||||||
|
@dbus.service.method('com.quexten.goldwarden.Autofill')
|
||||||
|
def autofill(self):
|
||||||
|
on_autofill()
|
||||||
|
return ""
|
||||||
|
|
||||||
|
DBusGMainLoop(set_as_default=True)
|
||||||
|
service = GoldwardenDBUSService()
|
|
@ -0,0 +1 @@
|
||||||
|
# todo
|
Loading…
Reference in New Issue