@@ -47,14 +47,39 @@ public abstract class Connection implements AutoCloseable {
4747
4848 private final int RESPONSE_TIMEOUT_S = 5 ;
4949
50+ private enum Message {
51+ SET_LOGIN ("set-login" ),
52+ GET_LOGINS ("get-logins" ),
53+ GENERATE_PASSWORD ("generate-password" ),
54+ ASSOCIATE ("associate" ),
55+ TEST_ASSOCIATE ("test-associate" ),
56+ GET_DATABASE_HASH ("get-databasehash" ),
57+ CHANGE_PUBLIC_KEYS ("change-public-keys" ),
58+ LOCK_DATABASE ("lock-database" ),
59+ DATABASE_LOCKED ("database-locked" ),
60+ DATABASE_UNLOCKED ("database-unlocked" ),
61+ GET_DATABASE_GROUPS ("get-database-groups" ),
62+ CREATE_NEW_GROUP ("create-new-group" ),
63+ GET_TOTP ("get-totp" ),
64+ REQUEST_AUTOTYPE ("request-autotype" ),
65+ PASSKEYS_REGISTER ("passkeys-register" ),
66+ PASSKEYS_GET ("passkeys-get" ),
67+ DELETE_ENTRY ("delete-entry" );
68+
69+ public final String action ;
70+
71+ Message (String action ) {
72+ this .action = action ;
73+ }
74+ }
5075 protected final String PROXY_NAME = "org.keepassxc.KeePassXC.BrowserServer" ;
5176 private static final String NOT_CONNECTED = "Not connected to KeePassXC. Call connect()." ;
5277 private static final String KEYEXCHANGE_MISSING = "Public keys need to be exchanged. Call changePublicKeys()." ;
5378 private static final String MISSING_CLASS = "Credentials have not been initialized" ;
5479 public static final String EXCEPTION_INFO = "Delaying association dialog response lookup due to https://github.com/keepassxreboot/keepassxc/issues/7099" ;
5580
5681 private static final Set <String > REQUESTS_WITHOUT_MANUAL_USER_INPUT = Set .of (
57- "change-public-keys" , "get-databasehash" , "test-associate" , "get-database-groups"
82+ Message . CHANGE_PUBLIC_KEYS . action , Message . GET_DATABASE_HASH . action , Message . TEST_ASSOCIATE . action , Message . GET_DATABASE_GROUPS . action
5883 );
5984
6085 public Connection () {
@@ -222,8 +247,8 @@ public void removePropertyChangeListener(PropertyChangeListener pcl) {
222247 */
223248 private boolean isSignal (JSONObject response ) {
224249 try {
225- return response .has ("action" ) && response .getString ("action" ).equals ("database-locked" )
226- || response .has ("action" ) && response .getString ("action" ).equals ("database-unlocked" );
250+ return response .has ("action" ) && response .getString ("action" ).equals (Message . DATABASE_LOCKED . action )
251+ || response .has ("action" ) && response .getString ("action" ).equals (Message . DATABASE_UNLOCKED . action );
227252 } catch (JSONException je ) {
228253 return false ;
229254 }
@@ -340,7 +365,7 @@ protected void changePublicKeys() throws IOException, KeepassProxyAccessExceptio
340365
341366 // Send change-public-keys request
342367 sendCleartextMessage (jsonTxt (Map .of (
343- "action" , "change-public-keys" ,
368+ "action" , Message . CHANGE_PUBLIC_KEYS . action ,
344369 "publicKey" , b64encode (keyPair .getPublicKey ()),
345370 "nonce" , b64encode (nonce ),
346371 "clientID" , clientID
@@ -349,7 +374,7 @@ protected void changePublicKeys() throws IOException, KeepassProxyAccessExceptio
349374 var response = new JSONObject ();
350375
351376 try {
352- response = executorService .submit (new MessageConsumer ("change-public-keys" , nonce )).get ();
377+ response = executorService .submit (new MessageConsumer (Message . CHANGE_PUBLIC_KEYS . action , nonce )).get ();
353378 } catch (InterruptedException | ExecutionException e ) {
354379 LOG .error (e .toString (), e .getCause ());
355380 }
@@ -383,7 +408,7 @@ public void associate() throws IOException, KeepassProxyAccessException {
383408
384409 // Send associate request
385410 var nonce = sendEncryptedMessage (Map .of (
386- "action" , "associate" ,
411+ "action" , Message . ASSOCIATE . action ,
387412 "key" , b64encode (keyPair .getPublicKey ()),
388413 "idKey" , b64encode (idKeyPair .getPublicKey ())
389414 ));
@@ -397,7 +422,7 @@ public void associate() throws IOException, KeepassProxyAccessException {
397422 Runnable lookupResponse = () -> {
398423 JSONObject response = null ;
399424 try {
400- response = getEncryptedResponseAndDecrypt ("associate" , nonce );
425+ response = getEncryptedResponseAndDecrypt (Message . ASSOCIATE . action , nonce );
401426 } catch (KeepassProxyAccessException e ) {
402427 LOG .error (e .toString (), e .getCause ());
403428 }
@@ -419,8 +444,8 @@ public void associate() throws IOException, KeepassProxyAccessException {
419444 */
420445 public String getDatabasehash () throws IOException , KeepassProxyAccessException {
421446 // Send get-databasehash request
422- var nonce = sendEncryptedMessage (Map .of ("action" , "get-databasehash" ));
423- var response = getEncryptedResponseAndDecrypt ("get-databasehash" , nonce );
447+ var nonce = sendEncryptedMessage (Map .of ("action" , Message . GET_DATABASE_HASH . action ));
448+ var response = getEncryptedResponseAndDecrypt (Message . GET_DATABASE_HASH . action , nonce );
424449
425450 return response .getString ("hash" );
426451 }
@@ -437,10 +462,10 @@ public String getDatabasehash() throws IOException, KeepassProxyAccessException
437462 public String getDatabasehash (boolean triggerUnlock ) throws IOException , KeepassProxyAccessException {
438463 // Send get-databasehash request with triggerUnlock, if needed
439464 var map = new HashMap <String , Object >(); // Map.of can't be used here, because we need a mutable object
440- map .put ("action" , "get-databasehash" );
465+ map .put ("action" , Message . GET_DATABASE_HASH . action );
441466 map .put ("triggerUnlock" , Boolean .toString (triggerUnlock ));
442467 var nonce = sendEncryptedMessage (map );
443- var response = getEncryptedResponseAndDecrypt ("get-databasehash" , nonce );
468+ var response = getEncryptedResponseAndDecrypt (Message . GET_DATABASE_HASH . action , nonce );
444469
445470 return response .getString ("hash" );
446471 }
@@ -458,11 +483,11 @@ public String getDatabasehash(boolean triggerUnlock) throws IOException, Keepass
458483 public void testAssociate (String id , String key ) throws IOException , KeepassProxyAccessException {
459484 // Send test-associate request
460485 var nonce = sendEncryptedMessage (Map .of (
461- "action" , "test-associate" ,
486+ "action" , Message . TEST_ASSOCIATE . action ,
462487 "id" , id ,
463488 "key" , key
464489 ));
465- getEncryptedResponseAndDecrypt ("test-associate" , nonce );
490+ getEncryptedResponseAndDecrypt (Message . TEST_ASSOCIATE . action , nonce );
466491
467492 }
468493
@@ -478,25 +503,17 @@ public void testAssociate(String id, String key) throws IOException, KeepassProx
478503 * @throws KeepassProxyAccessException No credentials found for the given URL.
479504 */
480505 public JSONObject getLogins (String url , String submitUrl , boolean httpAuth , List <Map <String , String >> list ) throws IOException , KeepassProxyAccessException {
481- var array = new JSONArray ();
482- // Syntax check for list
483- for (Map <String , String > m : list ) {
484- var o = new JSONObject (m );
485- if (!(o .has ("id" ) && o .has ("key" ) && o .length () == 2 )) {
486- throw new KeepassProxyAccessException ("JSON object key is malformed" );
487- }
488- array .put (m );
489- }
506+ var jsonArray = checkKeysList (list );
490507
491508 // Send get-logins
492509 var nonce = sendEncryptedMessage (Map .of (
493- "action" , "get-logins" ,
510+ "action" , Message . GET_LOGINS . action ,
494511 "url" , ensureNotNull (url ),
495512 "submitUrl" , ensureNotNull (submitUrl ),
496513 "httpAuth" , httpAuth ,
497- "keys" , array
514+ "keys" , jsonArray
498515 ));
499- return getEncryptedResponseAndDecrypt ("get-logins" , nonce );
516+ return getEncryptedResponseAndDecrypt (Message . GET_LOGINS . action , nonce );
500517
501518 }
502519
@@ -522,7 +539,7 @@ public JSONObject getLogins(String url, String submitUrl, boolean httpAuth, List
522539 public JSONObject setLogin (String url , String submitUrl , String id , String login , String password , String group , String groupUuid , String uuid ) throws IOException , KeepassProxyAccessException {
523540 // Send set-login
524541 var nonce = sendEncryptedMessage (Map .of (
525- "action" , "set-login" ,
542+ "action" , Message . SET_LOGIN . action ,
526543 "url" , ensureNotNull (url ),
527544 "submitUrl" , ensureNotNull (submitUrl ),
528545 "id" , ensureNotNull (id ),
@@ -532,7 +549,7 @@ public JSONObject setLogin(String url, String submitUrl, String id, String login
532549 "groupUuid" , ensureNotNull (groupUuid ),
533550 "uuid" , ensureNotNull (uuid )
534551 ));
535- return getEncryptedResponseAndDecrypt ("set-login" , nonce );
552+ return getEncryptedResponseAndDecrypt (Message . SET_LOGIN . action , nonce );
536553
537554 }
538555
@@ -545,8 +562,8 @@ public JSONObject setLogin(String url, String submitUrl, String id, String login
545562 */
546563 public JSONObject getDatabaseGroups () throws IOException , KeepassProxyAccessException {
547564 // Send get-database-groups
548- var nonce = sendEncryptedMessage (Map .of ("action" , "get-database-groups" ));
549- return getEncryptedResponseAndDecrypt ("get-database-groups" , nonce );
565+ var nonce = sendEncryptedMessage (Map .of ("action" , Message . GET_DATABASE_GROUPS . action ));
566+ return getEncryptedResponseAndDecrypt (Message . GET_DATABASE_GROUPS . action , nonce );
550567
551568 }
552569
@@ -560,10 +577,10 @@ public JSONObject getDatabaseGroups() throws IOException, KeepassProxyAccessExce
560577 public JSONObject generatePassword () throws IOException , KeepassProxyAccessException {
561578 // Send generate-password request
562579 var nonce = sendEncryptedMessage (Map .of (
563- "action" , "generate-password" ,
580+ "action" , Message . GENERATE_PASSWORD . action ,
564581 "clientID" , clientID
565582 ));
566- return getEncryptedResponseAndDecrypt ("generate-password" , nonce );
583+ return getEncryptedResponseAndDecrypt (Message . GENERATE_PASSWORD . action , nonce );
567584
568585 }
569586
@@ -576,8 +593,8 @@ public JSONObject generatePassword() throws IOException, KeepassProxyAccessExcep
576593 */
577594 public JSONObject lockDatabase () throws IOException , KeepassProxyAccessException {
578595 // Send lock-database request
579- var nonce = sendEncryptedMessage (Map .of ("action" , "lock-database" ));
580- return getEncryptedResponseAndDecrypt ("lock-database" , nonce );
596+ var nonce = sendEncryptedMessage (Map .of ("action" , Message . LOCK_DATABASE . action ));
597+ return getEncryptedResponseAndDecrypt (Message . LOCK_DATABASE . action , nonce );
581598
582599 }
583600
@@ -594,10 +611,10 @@ public JSONObject lockDatabase() throws IOException, KeepassProxyAccessException
594611 public JSONObject createNewGroup (String path ) throws IOException , KeepassProxyAccessException {
595612 // Send create-new-group request
596613 var nonce = sendEncryptedMessage (Map .of (
597- "action" , "create-new-group" ,
614+ "action" , Message . CREATE_NEW_GROUP . action ,
598615 "groupName" , ensureNotNull (path )
599616 ));
600- return getEncryptedResponseAndDecrypt ("create-new-group" , nonce );
617+ return getEncryptedResponseAndDecrypt (Message . CREATE_NEW_GROUP . action , nonce );
601618
602619 }
603620
@@ -613,10 +630,10 @@ public JSONObject createNewGroup(String path) throws IOException, KeepassProxyAc
613630 public JSONObject getTotp (String uuid ) throws IOException , KeepassProxyAccessException {
614631 // Send get-totp request
615632 var nonce = sendEncryptedMessage (Map .of (
616- "action" , "get-totp" ,
633+ "action" , Message . GET_TOTP . action ,
617634 "uuid" , ensureNotNull (uuid )
618635 ));
619- return getEncryptedResponseAndDecrypt ("get-totp" , nonce );
636+ return getEncryptedResponseAndDecrypt (Message . GET_TOTP . action , nonce );
620637
621638 }
622639
@@ -631,10 +648,10 @@ public JSONObject getTotp(String uuid) throws IOException, KeepassProxyAccessExc
631648 public JSONObject deleteEntry (String uuid ) throws IOException , KeepassProxyAccessException {
632649 // Send delete-entry request
633650 var nonce = sendEncryptedMessage (Map .of (
634- "action" , "delete-entry" ,
651+ "action" , Message . DELETE_ENTRY . action ,
635652 "uuid" , ensureNotNull (uuid )
636653 ));
637- return getEncryptedResponseAndDecrypt ("delete-entry" , nonce );
654+ return getEncryptedResponseAndDecrypt (Message . DELETE_ENTRY . action , nonce );
638655 }
639656
640657 /**
@@ -648,32 +665,24 @@ public JSONObject deleteEntry(String uuid) throws IOException, KeepassProxyAcces
648665 public JSONObject requestAutotype (String url ) throws IOException , KeepassProxyAccessException {
649666 // Send request-autotype request
650667 var nonce = sendEncryptedMessage (Map .of (
651- "action" , "request-autotype" ,
668+ "action" , Message . REQUEST_AUTOTYPE . action ,
652669 "groupName" , ensureNotNull (url )
653670 ));
654- return getEncryptedResponseAndDecrypt ("request-autotype" , nonce );
671+ return getEncryptedResponseAndDecrypt (Message . REQUEST_AUTOTYPE . action , nonce );
655672
656673 }
657674
658675 public JSONObject passkeysRegister (JSONObject publicKey , String origin , List <Map <String , String >> list ) throws IOException , KeepassProxyAccessException {
659- var array = new JSONArray ();
660- // Syntax check for list
661- for (Map <String , String > m : list ) {
662- var o = new JSONObject (m );
663- if (!(o .has ("id" ) && o .has ("key" ) && o .length () == 2 )) {
664- throw new KeepassProxyAccessException ("JSON object key is malformed" );
665- }
666- array .put (m );
667- }
676+ var jsonArray = checkKeysList (list );
668677
669678 // Send passkeys-register request
670679 var nonce = sendEncryptedMessage (Map .of (
671- "action" , "passkeys-register" ,
680+ "action" , Message . PASSKEYS_REGISTER . action ,
672681 "publicKey" , publicKey ,
673682 "origin" , ensureNotNull (origin ),
674- "keys" , array
683+ "keys" , jsonArray
675684 ));
676- return getEncryptedResponseAndDecrypt ("passkeys-register" , nonce );
685+ return getEncryptedResponseAndDecrypt (Message . PASSKEYS_REGISTER . action , nonce );
677686
678687 }
679688
@@ -743,6 +752,25 @@ private String ensureNotNull(String param) {
743752 return null == param ? "" : param ;
744753 }
745754
755+ /**
756+ * Syntax check for keys array.
757+ *
758+ * @param list A list of pairs of associateID and IDKeyPublicKey stored on association.
759+ * @return Transformed list as a JSONArray.
760+ * @throws KeepassProxyAccessException The JSON object key pair is malformed.
761+ */
762+ private JSONArray checkKeysList (List <Map <String , String >> list ) throws KeepassProxyAccessException {
763+ var array = new JSONArray ();
764+ for (Map <String , String > m : list ) {
765+ var o = new JSONObject (m );
766+ if (!(o .has ("id" ) && o .has ("key" ) && o .length () == 2 )) {
767+ throw new KeepassProxyAccessException ("JSON object key pair is malformed" );
768+ }
769+ array .put (m );
770+ }
771+ return array ;
772+ }
773+
746774 // Getters and Setters
747775 public String getIdKeyPairPublicKey () {
748776 return credentials .map (value -> b64encode (value .getIdKeyPublicKey ())).orElse ("" );
0 commit comments