diff options
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/progmodes/sql.el | 151 |
1 files changed, 150 insertions, 1 deletions
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el index 2df62585a0d..c72070b8923 100644 --- a/lisp/progmodes/sql.el +++ b/lisp/progmodes/sql.el | |||
| @@ -748,6 +748,126 @@ The package must be available to be loaded and activated." | |||
| 748 | (when (sql-is-indent-available) | 748 | (when (sql-is-indent-available) |
| 749 | (sqlind-minor-mode (if sql-use-indent-support +1 -1)))) | 749 | (sqlind-minor-mode (if sql-use-indent-support +1 -1)))) |
| 750 | 750 | ||
| 751 | ;; Secure Password wallet | ||
| 752 | |||
| 753 | (require 'auth-source) | ||
| 754 | |||
| 755 | (defun sql-auth-source-search-wallet (wallet product user server database port) | ||
| 756 | "Read auth source WALLET to locate the USER secret. | ||
| 757 | Sets `auth-sources' to WALLET and uses `auth-source-search' to locate the entry. | ||
| 758 | The DATABASE and SERVER are concatenated with a slash between them as the | ||
| 759 | host key." | ||
| 760 | (let* ((auth-sources wallet) | ||
| 761 | host | ||
| 762 | secret h-secret sd-secret) | ||
| 763 | |||
| 764 | ;; product | ||
| 765 | (setq product (symbol-name product)) | ||
| 766 | |||
| 767 | ;; user | ||
| 768 | (setq user (unless (string-empty-p user) user)) | ||
| 769 | |||
| 770 | ;; port | ||
| 771 | (setq port | ||
| 772 | (when (and port (numberp port) (not (zerop port))) | ||
| 773 | (number-to-string port))) | ||
| 774 | |||
| 775 | ;; server | ||
| 776 | (setq server (unless (string-empty-p server) server)) | ||
| 777 | |||
| 778 | ;; database | ||
| 779 | (setq database (unless (string-empty-p database) database)) | ||
| 780 | |||
| 781 | ;; host | ||
| 782 | (setq host (if server | ||
| 783 | (if database | ||
| 784 | (concat server "/" database) | ||
| 785 | server) | ||
| 786 | database)) | ||
| 787 | |||
| 788 | ;; Perform search | ||
| 789 | (dolist (s (auth-source-search :max 1000)) | ||
| 790 | (when (and | ||
| 791 | ;; Is PRODUCT specified, in the enty, and they are equal | ||
| 792 | (if product | ||
| 793 | (if (plist-member s :product) | ||
| 794 | (equal (plist-get s :product) product) | ||
| 795 | t) | ||
| 796 | t) | ||
| 797 | ;; Is USER specified, in the entry, and they are equal | ||
| 798 | (if user | ||
| 799 | (if (plist-member s :user) | ||
| 800 | (equal (plist-get s :user) user) | ||
| 801 | t) | ||
| 802 | t) | ||
| 803 | ;; Is PORT specified, in the entry, and they are equal | ||
| 804 | (if port | ||
| 805 | (if (plist-member s :port) | ||
| 806 | (equal (plist-get s :port) port) | ||
| 807 | t) | ||
| 808 | t)) | ||
| 809 | ;; Is HOST specified, in the entry, and they are equal | ||
| 810 | ;; then the H-SECRET list | ||
| 811 | (if (and host | ||
| 812 | (plist-member s :host) | ||
| 813 | (equal (plist-get s :host) host)) | ||
| 814 | (push s h-secret) | ||
| 815 | ;; Are SERVER and DATABASE specified, present, and equal | ||
| 816 | ;; then the SD-SECRET list | ||
| 817 | (if (and server | ||
| 818 | (plist-member s :server) | ||
| 819 | database | ||
| 820 | (plist-member s :database) | ||
| 821 | (equal (plist-get s :server) server) | ||
| 822 | (equal (plist-get s :database) database)) | ||
| 823 | (push s sd-secret) | ||
| 824 | ;; Is SERVER specified, in the entry, and they are equal | ||
| 825 | ;; then the base SECRET list | ||
| 826 | (if (and server | ||
| 827 | (plist-member s :server) | ||
| 828 | (equal (plist-get s :server) server)) | ||
| 829 | (push s secret) | ||
| 830 | ;; Is DATABASE specified, in the entry, and they are equal | ||
| 831 | ;; then the base SECRET list | ||
| 832 | (if (and database | ||
| 833 | (plist-member s :database) | ||
| 834 | (equal (plist-get s :database) database)) | ||
| 835 | (push s secret))))))) | ||
| 836 | (setq secret (or h-secret sd-secret secret)) | ||
| 837 | |||
| 838 | ;; If we found a single secret, return the password | ||
| 839 | (when (= 1 (length secret)) | ||
| 840 | (setq secret (car secret)) | ||
| 841 | (if (plist-member secret :secret) | ||
| 842 | (plist-get secret :secret) | ||
| 843 | nil)))) | ||
| 844 | |||
| 845 | (defcustom sql-password-wallet | ||
| 846 | (let (wallet w) | ||
| 847 | (dolist (ext '(".json.gpg" ".gpg" ".json" "") wallet) | ||
| 848 | (unless wallet | ||
| 849 | (setq w (locate-user-emacs-file (concat "sql-wallet" ext) | ||
| 850 | (concat ".sql-wallet" ext))) | ||
| 851 | (when (file-exists-p w) | ||
| 852 | (setq wallet w))))) | ||
| 853 | "Identification of the password wallet. | ||
| 854 | See `sql-password-search-wallet-function' to understand how this value | ||
| 855 | is used to locate the password wallet." | ||
| 856 | :type `(plist-get (symbol-plist 'auth-sources) 'custom-type) | ||
| 857 | :group 'SQL | ||
| 858 | :version "27.1") | ||
| 859 | |||
| 860 | (defvar sql-password-search-wallet-function #'sql-auth-source-search-wallet | ||
| 861 | "Function to handle the lookup of the database password. | ||
| 862 | The specified function will be called as: | ||
| 863 | (wallet-func WALLET PRODUCT USER SERVER DATABASE PORT) | ||
| 864 | |||
| 865 | It is expected to return either a string containing the password, | ||
| 866 | a function returning the password, or nil, If you want to support | ||
| 867 | another format of password file, then implement a different | ||
| 868 | search wallet function and identify the location of the password | ||
| 869 | store with `sql-password-wallet'.") | ||
| 870 | |||
| 751 | ;; misc customization of sql.el behavior | 871 | ;; misc customization of sql.el behavior |
| 752 | 872 | ||
| 753 | (defcustom sql-electric-stuff nil | 873 | (defcustom sql-electric-stuff nil |
| @@ -3199,6 +3319,10 @@ symbol `password', for the server if it contains the symbol | |||
| 3199 | `database'. The members of WHAT are processed in the order in | 3319 | `database'. The members of WHAT are processed in the order in |
| 3200 | which they are provided. | 3320 | which they are provided. |
| 3201 | 3321 | ||
| 3322 | If the `sql-password-wallet' is non-nil and WHAT contains the | ||
| 3323 | `password' token, then the `password' token will be pushed to the | ||
| 3324 | end to be sure that all of the values can be fed to the wallet. | ||
| 3325 | |||
| 3202 | Each token may also be a list with the token in the car and a | 3326 | Each token may also be a list with the token in the car and a |
| 3203 | plist of options as the cdr. The following properties are | 3327 | plist of options as the cdr. The following properties are |
| 3204 | supported: | 3328 | supported: |
| @@ -3210,6 +3334,15 @@ supported: | |||
| 3210 | 3334 | ||
| 3211 | In order to ask the user for username, password and database, call the | 3335 | In order to ask the user for username, password and database, call the |
| 3212 | function like this: (sql-get-login \\='user \\='password \\='database)." | 3336 | function like this: (sql-get-login \\='user \\='password \\='database)." |
| 3337 | |||
| 3338 | ;; Push the password to the end if we have a wallet | ||
| 3339 | (when (and sql-password-wallet | ||
| 3340 | (fboundp sql-password-search-wallet-function) | ||
| 3341 | (member 'password what)) | ||
| 3342 | (setq what (append (cl-delete 'password what) | ||
| 3343 | '(password)))) | ||
| 3344 | |||
| 3345 | ;; Prompt for each parameter | ||
| 3213 | (dolist (w what) | 3346 | (dolist (w what) |
| 3214 | (let ((plist (cdr-safe w))) | 3347 | (let ((plist (cdr-safe w))) |
| 3215 | (pcase (or (car-safe w) w) | 3348 | (pcase (or (car-safe w) w) |
| @@ -3218,7 +3351,19 @@ function like this: (sql-get-login \\='user \\='password \\='database)." | |||
| 3218 | 3351 | ||
| 3219 | ('password | 3352 | ('password |
| 3220 | (setq-default sql-password | 3353 | (setq-default sql-password |
| 3221 | (read-passwd "Password: " nil (sql-default-value 'sql-password)))) | 3354 | (if (and sql-password-wallet |
| 3355 | (fboundp sql-password-search-wallet-function)) | ||
| 3356 | (let ((password (funcall sql-password-search-wallet-function | ||
| 3357 | sql-password-wallet | ||
| 3358 | sql-product | ||
| 3359 | sql-user | ||
| 3360 | sql-server | ||
| 3361 | sql-database | ||
| 3362 | sql-port))) | ||
| 3363 | (if password | ||
| 3364 | password | ||
| 3365 | (read-passwd "Password: " nil (sql-default-value 'sql-password)))) | ||
| 3366 | (read-passwd "Password: " nil (sql-default-value 'sql-password))))) | ||
| 3222 | 3367 | ||
| 3223 | ('server | 3368 | ('server |
| 3224 | (sql-get-login-ext 'sql-server "Server: " 'sql-server-history plist)) | 3369 | (sql-get-login-ext 'sql-server "Server: " 'sql-server-history plist)) |
| @@ -4481,6 +4626,10 @@ the call to \\[sql-product-interactive] with | |||
| 4481 | (or sql-default-directory | 4626 | (or sql-default-directory |
| 4482 | default-directory))) | 4627 | default-directory))) |
| 4483 | 4628 | ||
| 4629 | ;; The password wallet returns a function which supplies the password. | ||
| 4630 | (when (functionp sql-password) | ||
| 4631 | (setq sql-password (funcall sql-password))) | ||
| 4632 | |||
| 4484 | ;; Call the COMINT service | 4633 | ;; Call the COMINT service |
| 4485 | (funcall (sql-get-product-feature product :sqli-comint-func) | 4634 | (funcall (sql-get-product-feature product :sqli-comint-func) |
| 4486 | product | 4635 | product |