Implement totp copy and url launch
This commit is contained in:
parent
ce17426063
commit
25b72e4c43
5 changed files with 60 additions and 7 deletions
|
|
@ -3,10 +3,7 @@ package actions
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pquerna/otp/totp"
|
|
||||||
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
|
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
|
||||||
"github.com/quexten/goldwarden/agent/config"
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
|
|
@ -72,9 +69,8 @@ func handleGetLoginCipher(request messages.IPCMessage, cfg *config.Config, vault
|
||||||
if !login.Login.Totp.IsNull() {
|
if !login.Login.Totp.IsNull() {
|
||||||
decryptedTotp, err := crypto.DecryptWith(login.Login.Totp, cipherKey)
|
decryptedTotp, err := crypto.DecryptWith(login.Login.Totp, cipherKey)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
code, err := totp.GenerateCode(string(strings.ReplaceAll(string(decryptedTotp), " ", "")), time.Now())
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
decryptedLogin.TwoFactorCode = code
|
decryptedLogin.TOTPSeed = string(decryptedTotp)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
@ -101,7 +97,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 access all credentials", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved {
|
if approved, err := pinentry.GetApproval("Access Vault", 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",
|
||||||
|
|
@ -124,6 +120,8 @@ 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{}
|
var decryptedPassword []byte = []byte{}
|
||||||
|
var decryptedTotp []byte = []byte{}
|
||||||
|
var decryptedURL []byte = []byte{}
|
||||||
|
|
||||||
if !login.Name.IsNull() {
|
if !login.Name.IsNull() {
|
||||||
decryptedName, err = crypto.DecryptWith(login.Name, key)
|
decryptedName, err = crypto.DecryptWith(login.Name, key)
|
||||||
|
|
@ -149,11 +147,29 @@ func handleListLoginsRequest(request messages.IPCMessage, cfg *config.Config, va
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !login.Login.Totp.IsNull() {
|
||||||
|
decryptedTotp, err = crypto.DecryptWith(login.Login.Totp, key)
|
||||||
|
if err != nil {
|
||||||
|
actionsLog.Warn("Could not decrypt login:" + err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !login.Login.URI.IsNull() {
|
||||||
|
decryptedURL, err = crypto.DecryptWith(login.Login.URI, 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),
|
Password: string(decryptedPassword),
|
||||||
|
TOTPSeed: string(decryptedTotp),
|
||||||
|
URI: string(decryptedURL),
|
||||||
})
|
})
|
||||||
|
|
||||||
// prevent deadlock from enclaves
|
// prevent deadlock from enclaves
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,8 @@ var listLoginsCmd = &cobra.Command{
|
||||||
"uuid": stringsx.Clean(login.UUID),
|
"uuid": stringsx.Clean(login.UUID),
|
||||||
"username": stringsx.Clean(login.Username),
|
"username": stringsx.Clean(login.Username),
|
||||||
"password": stringsx.Clean(strings.ReplaceAll(login.Password, "\"", "\\\"")),
|
"password": stringsx.Clean(strings.ReplaceAll(login.Password, "\"", "\\\"")),
|
||||||
|
"totp": stringsx.Clean(login.TOTPSeed),
|
||||||
|
"uri": stringsx.Clean(login.URI),
|
||||||
}
|
}
|
||||||
jsonString, err := json.Marshal(data)
|
jsonString, err := json.Marshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ type DecryptedLoginCipher struct {
|
||||||
UUID string
|
UUID string
|
||||||
OrgaizationID string
|
OrgaizationID string
|
||||||
Notes string
|
Notes string
|
||||||
TwoFactorCode string
|
TOTPSeed string
|
||||||
|
URI string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddLoginRequest struct {
|
type AddLoginRequest struct {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import clipboard
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import totp
|
||||||
Notify.init("Goldwarden")
|
Notify.init("Goldwarden")
|
||||||
|
|
||||||
class MyApp(Adw.Application):
|
class MyApp(Adw.Application):
|
||||||
|
|
@ -66,6 +67,8 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
action_row.password = i["password"]
|
action_row.password = i["password"]
|
||||||
action_row.username = i["username"]
|
action_row.username = i["username"]
|
||||||
action_row.uuid = i["uuid"]
|
action_row.uuid = i["uuid"]
|
||||||
|
action_row.uri = i["uri"]
|
||||||
|
action_row.totp = i["totp"]
|
||||||
self.history_list.append(action_row)
|
self.history_list.append(action_row)
|
||||||
self.starts_with_logins = None
|
self.starts_with_logins = None
|
||||||
self.other_logins = None
|
self.other_logins = None
|
||||||
|
|
@ -109,6 +112,17 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||||
return
|
return
|
||||||
item_uri = environment["vault"] + "#/vault?itemId=" + self.history_list.get_selected_row().uuid
|
item_uri = environment["vault"] + "#/vault?itemId=" + self.history_list.get_selected_row().uuid
|
||||||
Gtk.show_uri(None, item_uri, Gdk.CURRENT_TIME)
|
Gtk.show_uri(None, item_uri, Gdk.CURRENT_TIME)
|
||||||
|
elif keyval == 108:
|
||||||
|
print("launch")
|
||||||
|
print(self.history_list.get_selected_row().uri)
|
||||||
|
Gtk.show_uri(None, self.history_list.get_selected_row().uri, Gdk.CURRENT_TIME)
|
||||||
|
elif keyval == 116:
|
||||||
|
print("copy totp")
|
||||||
|
totp_code = totp.totp(self.history_list.get_selected_row().totp)
|
||||||
|
clipboard.write(totp_code)
|
||||||
|
notification=Notify.Notification.new("Goldwarden", "Totp Copied", "dialog-information")
|
||||||
|
notification.set_timeout(5)
|
||||||
|
notification.show()
|
||||||
|
|
||||||
keycont.connect('key-pressed', handle_keypress, self)
|
keycont.connect('key-pressed', handle_keypress, self)
|
||||||
self.add_controller(keycont)
|
self.add_controller(keycont)
|
||||||
|
|
|
||||||
20
ui/totp.py
Normal file
20
ui/totp.py
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# https://github.com/susam/mintotp
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import hmac
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
def hotp(key, counter, digits=6, digest='sha1'):
|
||||||
|
key = base64.b32decode(key.upper() + '=' * ((8 - len(key)) % 8))
|
||||||
|
counter = struct.pack('>Q', counter)
|
||||||
|
mac = hmac.new(key, counter, digest).digest()
|
||||||
|
offset = mac[-1] & 0x0f
|
||||||
|
binary = struct.unpack('>L', mac[offset:offset+4])[0] & 0x7fffffff
|
||||||
|
return str(binary)[-digits:].zfill(digits)
|
||||||
|
|
||||||
|
|
||||||
|
def totp(key, time_step=30, digits=6, digest='sha1'):
|
||||||
|
return hotp(key, int(time.time() / time_step), digits, digest)
|
||||||
Loading…
Reference in a new issue