diff --git a/app/src/main/java/io/xpipe/app/pwman/PasswordManager.java b/app/src/main/java/io/xpipe/app/pwman/PasswordManager.java index 047f481c6..dd5caa208 100644 --- a/app/src/main/java/io/xpipe/app/pwman/PasswordManager.java +++ b/app/src/main/java/io/xpipe/app/pwman/PasswordManager.java @@ -78,6 +78,7 @@ public interface PasswordManager { l.add(EnpassPasswordManager.class); } l.add(DashlanePasswordManager.class); + l.add(PassworkPasswordManager.class); l.add(PsonoPasswordManager.class); l.add(PassboltPasswordManager.class); if (OsType.ofLocal() == OsType.WINDOWS) { diff --git a/app/src/main/java/io/xpipe/app/pwman/PassworkPasswordManager.java b/app/src/main/java/io/xpipe/app/pwman/PassworkPasswordManager.java new file mode 100644 index 000000000..478c9fbeb --- /dev/null +++ b/app/src/main/java/io/xpipe/app/pwman/PassworkPasswordManager.java @@ -0,0 +1,163 @@ +package io.xpipe.app.pwman; + +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.JsonNode; +import io.xpipe.app.comp.base.SecretFieldComp; +import io.xpipe.app.comp.base.TextFieldComp; +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.ext.ProcessControlProvider; +import io.xpipe.app.issue.ErrorEventFactory; +import io.xpipe.app.platform.OptionsBuilder; +import io.xpipe.app.prefs.PasswordManagerTestComp; +import io.xpipe.app.process.CommandBuilder; +import io.xpipe.app.process.CommandSupport; +import io.xpipe.app.process.LocalShell; +import io.xpipe.app.process.ShellControl; +import io.xpipe.core.InPlaceSecretValue; +import io.xpipe.core.JacksonMapper; +import javafx.beans.property.Property; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import lombok.extern.jackson.Jacksonized; + +import java.util.Optional; + +@Getter +@Builder +@ToString +@Jacksonized +@JsonTypeName("passwork") +public class PassworkPasswordManager implements PasswordManager { + + private static ShellControl SHELL; + + private final String serverUrl; + private final InPlaceSecretValue token; + private final InPlaceSecretValue masterKey; + + @Override + public boolean supportsKeyConfiguration() { + return false; + } + + @Override + public boolean selectInitial() throws Exception { + return LocalShell.getShell().view().findProgram("passwork-cli").isPresent(); + } + + @Override + public PasswordManagerKeyConfiguration getKeyConfiguration() { + return PasswordManagerKeyConfiguration.none(); + } + + @SuppressWarnings("unused") + public static OptionsBuilder createOptions(Property p) { + var serverUrl = new SimpleStringProperty(p.getValue().getServerUrl()); + var token = new SimpleObjectProperty<>(p.getValue().getToken()); + var masterKey = new SimpleObjectProperty<>(p.getValue().getMasterKey()); + return new OptionsBuilder() + .nameAndDescription("passworkServerUrl") + .addComp( + new TextFieldComp(serverUrl) + .apply(struc -> { + struc.setPromptText("https://myorg.passwork.io"); + }) + .maxWidth(600), + serverUrl) + .nonNull() + .nameAndDescription("passworkAccessToken") + .addComp(new SecretFieldComp(token, false).maxWidth(600), token) + .nonNull() + .nameAndDescription("passworkMasterKey") + .addComp(new SecretFieldComp(masterKey, false).maxWidth(600), masterKey) + .nonNull() + .nameAndDescription("passwordManagerTest") + .addComp(new PasswordManagerTestComp(true)) + .bind( + () -> { + return PassworkPasswordManager.builder() + .token(token.get()) + .masterKey(masterKey.get()) + .serverUrl(serverUrl.get()) + .build(); + }, + p); + } + + private static synchronized ShellControl getOrStartShell() throws Exception { + if (SHELL == null) { + SHELL = ProcessControlProvider.get().createLocalProcessControl(true); + } + SHELL.start(); + return SHELL; + } + + @Override + public synchronized Result query(String key) { + if (serverUrl == null || token == null || masterKey == null) { + return null; + } + + try { + CommandSupport.isInLocalPathOrThrow("Passwork CLI", "passwork-cli"); + } catch (Exception e) { + ErrorEventFactory.fromThrowable(e) + .expected() + .link("https://passwork.pro/user-guides/api-and-integrations/passwork-cli/") + .handle(); + return null; + } + + try { + var fixedServerUrl = serverUrl.startsWith("http") ? serverUrl : "https://" + serverUrl; + getOrStartShell().view().setSensitiveEnvironmentVariable("PASSWORK_HOST", fixedServerUrl); + getOrStartShell().view().setSensitiveEnvironmentVariable("PASSWORK_TOKEN", token.getSecretValue()); + getOrStartShell() + .view() + .setSensitiveEnvironmentVariable("PASSWORK_MASTER_KEY", masterKey.getSecretValue()); + var user = getOrStartShell() + .command(CommandBuilder.of() + .add("passwork-cli") + .add("get") + .add("--password-id") + .addQuoted(key) + .add("--field", "login")) + .sensitive() + .readStdoutOrThrow(); + if ("None".equals(user)) { + user = null; + } + + var pass = getOrStartShell() + .command(CommandBuilder.of() + .add("passwork-cli") + .add("get") + .add("--password-id") + .addQuoted(key) + .add("--field", "password")) + .sensitive() + .readStdoutOrThrow(); + if ("None".equals(pass)) { + pass = null; + } + + return Result.of(Credentials.of(user, pass), null); + } catch (Exception e) { + ErrorEventFactory.fromThrowable(e).handle(); + return null; + } + } + + @Override + public String getKeyPlaceholder() { + return AppI18n.get("passworkPlaceholder"); + } + + @Override + public String getWebsite() { + return "https://passwork.pro/"; + } +} diff --git a/app/src/main/java/io/xpipe/app/pwman/PsonoPasswordManager.java b/app/src/main/java/io/xpipe/app/pwman/PsonoPasswordManager.java index dc89ddb59..4afee90a5 100644 --- a/app/src/main/java/io/xpipe/app/pwman/PsonoPasswordManager.java +++ b/app/src/main/java/io/xpipe/app/pwman/PsonoPasswordManager.java @@ -68,10 +68,13 @@ public class PsonoPasswordManager implements PasswordManager { }) .maxWidth(600), serverUrl) + .nonNull() .nameAndDescription("psonoApiKey") .addComp(new SecretFieldComp(apiKey, false).maxWidth(600), apiKey) + .nonNull() .nameAndDescription("psonoApiSecretKey") .addComp(new SecretFieldComp(apiSecretKey, false).maxWidth(600), apiSecretKey) + .nonNull() .nameAndDescription("passwordManagerTest") .addComp(new PasswordManagerTestComp(true)) .bind( diff --git a/lang/strings/fixed_en.properties b/lang/strings/fixed_en.properties index eabac7b2d..47eae7b7f 100644 --- a/lang/strings/fixed_en.properties +++ b/lang/strings/fixed_en.properties @@ -166,4 +166,6 @@ hashicorpVaultPlaceholder=/path/to/secret?user=&pass=&private-key= hashicorpVault=Hashicorp Vault protonPassPasswordPlaceholder=Vault Name/Item name protonPass=Proton Pass +passwork=Passwork +passworkPlaceholder=Item ID diff --git a/lang/strings/translations_da.properties b/lang/strings/translations_da.properties index ecf85b089..0c2fb3afe 100644 --- a/lang/strings/translations_da.properties +++ b/lang/strings/translations_da.properties @@ -1475,6 +1475,12 @@ enpassVaultFileDescription=Den lokale Enpass vault-fil. flat=Flad recursive=Rekursiv rdpAllowListBlocked=Den valgte RemoteApp er ikke inkluderet i listen over tilladte RDP'er for serveren og kan ikke startes. +passworkServerUrl=Server-URL +passworkServerUrlDescription=URL til password-backend-serveren +passworkAccessToken=API-adgangstoken +passworkAccessTokenDescription=Det API-adgangstoken, der skal bruges +passworkMasterKey=API-hovednøgle +passworkMasterKeyDescription=Den API-masternøgle, der skal bruges psonoServerUrl=Server-URL psonoServerUrlDescription=URL til psono-backend-serveren psonoApiKey=API-nøgle diff --git a/lang/strings/translations_de.properties b/lang/strings/translations_de.properties index f6d887a9e..9ed8f09e0 100644 --- a/lang/strings/translations_de.properties +++ b/lang/strings/translations_de.properties @@ -1468,6 +1468,12 @@ enpassVaultFileDescription=Die lokale Enpass-Tresordatei. flat=Flach recursive=Rekursiv rdpAllowListBlocked=Die ausgewählte RemoteApp ist nicht in der RDP-Zulassungsliste für den Server enthalten und kann nicht gestartet werden. +passworkServerUrl=Server-URL +passworkServerUrlDescription=URL des Passwort-Backend-Servers +passworkAccessToken=API-Zugriffstoken +passworkAccessTokenDescription=Das zu verwendende API-Zugangs-Token +passworkMasterKey=API-Hauptschlüssel +passworkMasterKeyDescription=Der zu verwendende API-Hauptschlüssel psonoServerUrl=Server-URL psonoServerUrlDescription=URL des Psono-Backend-Servers psonoApiKey=API-Schlüssel diff --git a/lang/strings/translations_en.properties b/lang/strings/translations_en.properties index eb36a68ec..b1b157faa 100644 --- a/lang/strings/translations_en.properties +++ b/lang/strings/translations_en.properties @@ -1499,6 +1499,12 @@ enpassVaultFileDescription=The local Enpass vault file. flat=Flat recursive=Recursive rdpAllowListBlocked=The selected RemoteApp is not included in the RDP allow list for the server and can't be launched. +passworkServerUrl=Server URL +passworkServerUrlDescription=URL of the password backend server +passworkAccessToken=API access token +passworkAccessTokenDescription=The API access token to use +passworkMasterKey=API master key +passworkMasterKeyDescription=The API master key to use psonoServerUrl=Server URL psonoServerUrlDescription=URL of the psono backend server psonoApiKey=API Key diff --git a/lang/strings/translations_es.properties b/lang/strings/translations_es.properties index 71eafe8a7..f9e4d46a7 100644 --- a/lang/strings/translations_es.properties +++ b/lang/strings/translations_es.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=El archivo local de la bóveda de Enpass. flat=Plano recursive=Recursivo rdpAllowListBlocked=La RemoteApp seleccionada no está incluida en la lista de RDP permitidos para el servidor y no se puede iniciar. +passworkServerUrl=URL del servidor +passworkServerUrlDescription=URL del servidor de contraseñas +passworkAccessToken=Token de acceso a la API +passworkAccessTokenDescription=El token de acceso a la API que hay que utilizar +passworkMasterKey=Clave maestra API +passworkMasterKeyDescription=La clave maestra API a utilizar psonoServerUrl=URL del servidor psonoServerUrlDescription=URL del servidor psono backend psonoApiKey=Clave API diff --git a/lang/strings/translations_fr.properties b/lang/strings/translations_fr.properties index 73bb5d99f..1a8c0e8b8 100644 --- a/lang/strings/translations_fr.properties +++ b/lang/strings/translations_fr.properties @@ -1473,6 +1473,12 @@ enpassVaultFileDescription=Le fichier local du coffre-fort Enpass. flat=Appartement recursive=Récursif rdpAllowListBlocked=La RemoteApp sélectionnée n'est pas incluse dans la liste des autorisations RDP pour le serveur et ne peut pas être lancée. +passworkServerUrl=URL du serveur +passworkServerUrlDescription=URL du serveur de backend du mot de passe +passworkAccessToken=Jeton d'accès à l'API +passworkAccessTokenDescription=Le jeton d'accès à l'API à utiliser +passworkMasterKey=Clé principale de l'API +passworkMasterKeyDescription=La clé principale de l'API à utiliser psonoServerUrl=URL du serveur psonoServerUrlDescription=URL du serveur backend psono psonoApiKey=Clé API diff --git a/lang/strings/translations_id.properties b/lang/strings/translations_id.properties index 5228cda02..eb17f79e0 100644 --- a/lang/strings/translations_id.properties +++ b/lang/strings/translations_id.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=File brankas Enpass lokal. flat=Datar recursive=Rekursif rdpAllowListBlocked=RemoteApp yang dipilih tidak termasuk dalam daftar izin RDP untuk server dan tidak dapat diluncurkan. +passworkServerUrl=URL server +passworkServerUrlDescription=URL server backend kata sandi +passworkAccessToken=Token akses API +passworkAccessTokenDescription=Token akses API untuk digunakan +passworkMasterKey=Kunci master API +passworkMasterKeyDescription=Kunci utama API untuk digunakan psonoServerUrl=URL server psonoServerUrlDescription=URL server backend psono psonoApiKey=Kunci API diff --git a/lang/strings/translations_it.properties b/lang/strings/translations_it.properties index 8edfe8a86..11b83946a 100644 --- a/lang/strings/translations_it.properties +++ b/lang/strings/translations_it.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=Il file del caveau Enpass locale. flat=Piatto recursive=Ricorsivo rdpAllowListBlocked=La RemoteApp selezionata non è inclusa nell'elenco dei permessi RDP del server e non può essere lanciata. +passworkServerUrl=URL del server +passworkServerUrlDescription=URL del server backend delle password +passworkAccessToken=Token di accesso API +passworkAccessTokenDescription=Il token di accesso all'API da utilizzare +passworkMasterKey=Chiave master API +passworkMasterKeyDescription=La chiave master API da utilizzare psonoServerUrl=URL del server psonoServerUrlDescription=URL del server backend di psono psonoApiKey=Chiave API diff --git a/lang/strings/translations_ja.properties b/lang/strings/translations_ja.properties index ac7be2004..547dc4173 100644 --- a/lang/strings/translations_ja.properties +++ b/lang/strings/translations_ja.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=ローカルのEnpass保管庫ファイル。 flat=フラット recursive=再帰的 rdpAllowListBlocked=選択したRemoteAppがサーバーのRDP許可リストに含まれておらず、起動できない。 +passworkServerUrl=サーバーURL +passworkServerUrlDescription=パスワードバックエンドサーバーのURL +passworkAccessToken=APIアクセストークン +passworkAccessTokenDescription=使用するAPIアクセストークン +passworkMasterKey=APIマスターキー +passworkMasterKeyDescription=使用するAPIマスターキー psonoServerUrl=サーバーURL psonoServerUrlDescription=psonoバックエンドサーバのURL psonoApiKey=APIキー diff --git a/lang/strings/translations_ko.properties b/lang/strings/translations_ko.properties index d062212f4..8a0a66cb7 100644 --- a/lang/strings/translations_ko.properties +++ b/lang/strings/translations_ko.properties @@ -1479,6 +1479,12 @@ flat=이 파일에만 적용 #custom recursive=하위 폴더에도 적용 rdpAllowListBlocked=선택한 RemoteApp이 서버의 RDP 허용 목록에 포함되어 있지 않으므로 시작할 수 없습니다. +passworkServerUrl=서버 URL +passworkServerUrlDescription=비밀번호 백엔드 서버의 URL +passworkAccessToken=API 액세스 토큰 +passworkAccessTokenDescription=사용할 API 액세스 토큰 +passworkMasterKey=API 마스터 키 +passworkMasterKeyDescription=사용할 API 마스터 키 psonoServerUrl=서버 URL psonoServerUrlDescription=Psono 백엔드 서버의 URL psonoApiKey=API 키 diff --git a/lang/strings/translations_nl.properties b/lang/strings/translations_nl.properties index dc98a10af..97eb86005 100644 --- a/lang/strings/translations_nl.properties +++ b/lang/strings/translations_nl.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=Het lokale Enpass kluisbestand. flat=Plat recursive=Recursief rdpAllowListBlocked=De geselecteerde RemoteApp is niet opgenomen in de RDP allow lijst voor de server en kan niet worden gestart. +passworkServerUrl=Server URL +passworkServerUrlDescription=URL van de achterliggende wachtwoordserver +passworkAccessToken=API toegangstoken +passworkAccessTokenDescription=Het API toegangstoken om te gebruiken +passworkMasterKey=API-hoofdsleutel +passworkMasterKeyDescription=De te gebruiken API-hoofdsleutel psonoServerUrl=Server URL psonoServerUrlDescription=URL van de psono backend server psonoApiKey=API-sleutel diff --git a/lang/strings/translations_pl.properties b/lang/strings/translations_pl.properties index 9fc81025d..353fb6dc2 100644 --- a/lang/strings/translations_pl.properties +++ b/lang/strings/translations_pl.properties @@ -1435,6 +1435,12 @@ enpassVaultFileDescription=Lokalny plik sejfu Enpass. flat=Płaski recursive=Rekursywny rdpAllowListBlocked=Wybrana aplikacja RemoteApp nie znajduje się na liście zezwoleń RDP dla serwera i nie można jej uruchomić. +passworkServerUrl=Adres URL serwera +passworkServerUrlDescription=Adres URL serwera zaplecza haseł +passworkAccessToken=Token dostępu API +passworkAccessTokenDescription=Token dostępu API do użycia +passworkMasterKey=Klucz główny API +passworkMasterKeyDescription=Klucz główny API do użycia psonoServerUrl=Adres URL serwera psonoServerUrlDescription=Adres URL serwera backend psono psonoApiKey=Klucz API diff --git a/lang/strings/translations_pt.properties b/lang/strings/translations_pt.properties index 188ddbd30..33742fe8b 100644 --- a/lang/strings/translations_pt.properties +++ b/lang/strings/translations_pt.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=O ficheiro local do cofre do Enpass. flat=Plano recursive=Recursivo rdpAllowListBlocked=A RemoteApp selecionada não está incluída na lista de permissões RDP do servidor e não pode ser iniciada. +passworkServerUrl=URL do servidor +passworkServerUrlDescription=URL do servidor backend da palavra-passe +passworkAccessToken=Token de acesso à API +passworkAccessTokenDescription=O token de acesso à API a utilizar +passworkMasterKey=Chave mestra da API +passworkMasterKeyDescription=A chave mestra da API a utilizar psonoServerUrl=URL do servidor psonoServerUrlDescription=URL do servidor backend psono psonoApiKey=Chave API diff --git a/lang/strings/translations_ru.properties b/lang/strings/translations_ru.properties index 756fb2b3b..8d18c9b51 100644 --- a/lang/strings/translations_ru.properties +++ b/lang/strings/translations_ru.properties @@ -1538,6 +1538,12 @@ enpassVaultFileDescription=Локальный файл хранилища Enpass flat=Плоский recursive=Рекурсивный rdpAllowListBlocked=Выбранное RemoteApp не включено в список разрешенных RDP для сервера и не может быть запущено. +passworkServerUrl=URL-адрес сервера +passworkServerUrlDescription=URL-адрес внутреннего сервера паролей +passworkAccessToken=Токен доступа к API +passworkAccessTokenDescription=Токен доступа к API, который нужно использовать +passworkMasterKey=Мастер-ключ API +passworkMasterKeyDescription=Мастер-ключ API, который нужно использовать psonoServerUrl=URL-адрес сервера psonoServerUrlDescription=URL-адрес внутреннего сервера psono psonoApiKey=Ключ API diff --git a/lang/strings/translations_sv.properties b/lang/strings/translations_sv.properties index 6c9b7b748..d12595d7d 100644 --- a/lang/strings/translations_sv.properties +++ b/lang/strings/translations_sv.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=Den lokala Enpass-valvfilen. flat=Platt recursive=Rekursiv rdpAllowListBlocked=Den valda RemoteApp finns inte med i listan över RDP-tillåtna program för servern och kan inte startas. +passworkServerUrl=URL till server +passworkServerUrlDescription=URL för backend-servern för lösenord +passworkAccessToken=Token för API-åtkomst +passworkAccessTokenDescription=Den API-åtkomsttoken som ska användas +passworkMasterKey=API huvudnyckel +passworkMasterKeyDescription=Den API-huvudnyckel som ska användas psonoServerUrl=URL till server psonoServerUrlDescription=URL för backend-servern för psono psonoApiKey=API-nyckel diff --git a/lang/strings/translations_tr.properties b/lang/strings/translations_tr.properties index 945898c51..658b550f3 100644 --- a/lang/strings/translations_tr.properties +++ b/lang/strings/translations_tr.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=Yerel Enpass kasa dosyası. flat=Düz recursive=Yinelemeli rdpAllowListBlocked=Seçilen RemoteApp, sunucu için RDP izin verilenler listesine dahil edilmemiştir ve başlatılamaz. +passworkServerUrl=Sunucu URL'si +passworkServerUrlDescription=Parola arka uç sunucusunun URL'si +passworkAccessToken=API erişim belirteci +passworkAccessTokenDescription=Kullanılacak API erişim belirteci +passworkMasterKey=API ana anahtarı +passworkMasterKeyDescription=Kullanılacak API ana anahtarı psonoServerUrl=Sunucu URL'si psonoServerUrlDescription=Psono arka uç sunucusunun URL'si psonoApiKey=API Anahtarı diff --git a/lang/strings/translations_vi.properties b/lang/strings/translations_vi.properties index 2f8c1e5e4..203b09672 100644 --- a/lang/strings/translations_vi.properties +++ b/lang/strings/translations_vi.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=Tệp kho lưu trữ Enpass cục bộ. flat=Phẳng recursive=Đệ quy rdpAllowListBlocked=Ứng dụng RemoteApp đã chọn không có trong danh sách cho phép RDP của máy chủ nên không thể khởi chạy được. +passworkServerUrl=URL máy chủ +passworkServerUrlDescription=URL của máy chủ quản lý mật khẩu +passworkAccessToken=Mã thông báo truy cập API +passworkAccessTokenDescription=Token truy cập API cần sử dụng +passworkMasterKey=Khóa chính API +passworkMasterKeyDescription=Khóa chính API cần sử dụng psonoServerUrl=URL máy chủ psonoServerUrlDescription=Địa chỉ URL của máy chủ backend psono psonoApiKey=Khóa API diff --git a/lang/strings/translations_zh-Hans.properties b/lang/strings/translations_zh-Hans.properties index a544401b1..875694062 100644 --- a/lang/strings/translations_zh-Hans.properties +++ b/lang/strings/translations_zh-Hans.properties @@ -1976,6 +1976,12 @@ flat=仅当前层 #custom recursive=全部层级 rdpAllowListBlocked=所选 RemoteApp 未包含在服务器的 RDP 允许列表中,因此无法启动。 +passworkServerUrl=服务器 URL +passworkServerUrlDescription=密码后端服务器的 URL +passworkAccessToken=API 访问令牌 +passworkAccessTokenDescription=要使用的 API 访问令牌 +passworkMasterKey=API 主密钥 +passworkMasterKeyDescription=使用的 API 主密钥 psonoServerUrl=服务器 URL #custom psonoServerUrlDescription=Psono 后端服务器 URL diff --git a/lang/strings/translations_zh-Hant.properties b/lang/strings/translations_zh-Hant.properties index dc39fca33..ef50c31e1 100644 --- a/lang/strings/translations_zh-Hant.properties +++ b/lang/strings/translations_zh-Hant.properties @@ -1434,6 +1434,12 @@ enpassVaultFileDescription=本機 Enpass 保險庫檔案。 flat=扁平 recursive=遞歸 rdpAllowListBlocked=選取的 RemoteApp 未包含在伺服器的 RDP 允許清單中,因此無法啟動。 +passworkServerUrl=伺服器 URL +passworkServerUrlDescription=密碼後端伺服器的 URL +passworkAccessToken=API 存取標記 +passworkAccessTokenDescription=要使用的 API 存取代碼 +passworkMasterKey=API 主密碼 +passworkMasterKeyDescription=使用的 API 主金鑰 psonoServerUrl=伺服器 URL psonoServerUrlDescription=psono 後端伺服器的 URL psonoApiKey=API 金鑰