<commit_before>;;;; SPDX-FileCopyrightText: Atlas Engineer LLC
;;;; SPDX-License-Identifier: BSD-3-Clause

(in-package :password)

(define-class keepassxc-interface (password-interface)
  ((executable (pathname->string (sera:resolve-executable "keepassxc-cli")))
   (password-file)
   (master-password nil
                    :type (or null string)))
  (:export-class-name-p t)
  (:export-accessor-names-p t)
  (:accessor-name-transformer (hu.dwim.defclass-star:make-name-transformer name)))

(push 'keepassxc-interface *interfaces*)

(defmethod list-passwords ((password-interface keepassxc-interface))
  (let* ((st (make-string-input-stream (master-password password-interface)))
         (output (execute password-interface (list "ls" (password-file password-interface))
                          :input st :output '(:string :stripped t))))
    (remove "Recycle Bin/" (rest (cl-ppcre:split "\\n" output)) :test #'equal)))

(defmethod clip-password ((password-interface keepassxc-interface) &key password-name service)
  (declare (ignore service))
  (with-input-from-string (st (master-password password-interface))
    (execute password-interface (list "clip"
                                      (password-file password-interface)
                                      password-name
                                      ;; Timeout for password
                                      (format nil "~a" (sleep-timer password-interface)))
      :input st :output '(:string :stripped t))))

(defmethod clip-username ((password-interface keepassxc-interface) &key password-name service)
  (declare (ignore service))
  (with-input-from-string (st (master-password password-interface))
    (execute password-interface (list "clip"
                                      "--attribute" "username"
                                      (password-file password-interface)
                                      password-name
                                      ;; Timeout for password
                                      (format nil "~a" (sleep-timer password-interface)))
             :input st :output '(:string :stripped t))))

(defmethod save-password ((password-interface keepassxc-interface)
                          &key password-name username password service)
  (declare (ignore service))
  (with-input-from-string (st (format nil "~a~C~a"
                                      (master-password password-interface)
                                      #\newline password))
    (execute password-interface (list "add"
                                      "--username" username
                                      "--password-prompt" (password-file password-interface)
                                      (if (str:emptyp password-name)
                                          "--generate"
                                          password-name))
             :input st)))

(defmethod password-correct-p ((password-interface keepassxc-interface))
  (when (master-password password-interface)
    (handler-case
        (let* ((st (make-string-input-stream (master-password password-interface)))
               (output (execute password-interface (list "ls" (password-file password-interface))
                                :input st :output '(:string :stripped t))))
          (remove "Recycle Bin/" (rest (cl-ppcre:split "\\n" output)) :test #'equal))
      (uiop/run-program:subprocess-error ()
        nil))))
<commit_msg>Password Manager Bridge (KeepassXC): Bug Fix<commit_after>;;;; SPDX-FileCopyrightText: Atlas Engineer LLC
;;;; SPDX-License-Identifier: BSD-3-Clause

(in-package :password)

(define-class keepassxc-interface (password-interface)
  ((executable (pathname->string (sera:resolve-executable "keepassxc-cli")))
   (password-file)
   (master-password nil
                    :type (or null string)))
  (:export-class-name-p t)
  (:export-accessor-names-p t)
  (:accessor-name-transformer (hu.dwim.defclass-star:make-name-transformer name)))

(push 'keepassxc-interface *interfaces*)

(defmethod list-passwords ((password-interface keepassxc-interface))
  (let* ((st (make-string-input-stream (master-password password-interface)))
         (output (execute password-interface (list "ls" (password-file password-interface))
                          :input st :output '(:string :stripped t))))
    (remove "Recycle Bin/" (sera:lines output) :test #'equal)))

(defmethod clip-password ((password-interface keepassxc-interface) &key password-name service)
  (declare (ignore service))
  (with-input-from-string (st (master-password password-interface))
    (execute password-interface (list "clip"
                                      (password-file password-interface)
                                      password-name
                                      ;; Timeout for password
                                      (format nil "~a" (sleep-timer password-interface)))
      :input st :output '(:string :stripped t))))

(defmethod clip-username ((password-interface keepassxc-interface) &key password-name service)
  (declare (ignore service))
  (with-input-from-string (st (master-password password-interface))
    (execute password-interface (list "clip"
                                      "--attribute" "username"
                                      (password-file password-interface)
                                      password-name
                                      ;; Timeout for password
                                      (format nil "~a" (sleep-timer password-interface)))
             :input st :output '(:string :stripped t))))

(defmethod save-password ((password-interface keepassxc-interface)
                          &key password-name username password service)
  (declare (ignore service))
  (with-input-from-string (st (format nil "~a~C~a"
                                      (master-password password-interface)
                                      #\newline password))
    (execute password-interface (list "add"
                                      "--username" username
                                      "--password-prompt" (password-file password-interface)
                                      (if (str:emptyp password-name)
                                          "--generate"
                                          password-name))
             :input st)))

(defmethod password-correct-p ((password-interface keepassxc-interface))
  (when (master-password password-interface)
    (handler-case
        (let* ((st (make-string-input-stream (master-password password-interface)))
               (output (execute password-interface (list "ls" (password-file password-interface))
                                :input st :output '(:string :stripped t))))
          (remove "Recycle Bin/" (rest (cl-ppcre:split "\\n" output)) :test #'equal))
      (uiop/run-program:subprocess-error ()
        nil))))

{'fraction_non_alphanumeric': 0.11933797909407666, 'fraction_numerical': 0.00029036004645760743, 'mean_word_length': 1.8716131721550646, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 42, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6074526', 'n_tokens_mistral': 1729, 'n_tokens_neox': 1663, 'n_words': 423}