From 13aa217bacf43ef70b68e5287e714366e77ae61d Mon Sep 17 00:00:00 2001 From: Ken Manheimer Date: Mon, 4 Jul 2011 18:16:10 -0400 Subject: [PATCH] * allout.el (allout-encrypt-unencrypted-on-saves): Do not provide insecure exception for current topic. Also note that auto-saves are handled differently. (allout-auto-save-temporarily-disabled), (allout-just-did-undo): State variables for tracking auto-save inhibition situation. (allout-write-contents-hook-handler): Rename from 'allout-write-file-hook-handler', and describe how it depends on write-contents-functions sensitivity to non-nil value to prevent file write. (allout-auto-save-hook-handler): Remove. auto-save does not check this in individual buffers, only in the starting buffer, so this is not the right way for us to inhibit auto-save in a buffer according to its condition. (allout-mode): Use new allout-write-contents-hook-handler, and only with write-contents-functions. Remove auto-save provisions - they're implemented elsewhere. (allout-before-change-handler): If undo is in progress, note that for attention of allout-post-command-business. (allout-post-command-business): If the command we're following was an undo, check for change in the status of encrypted items and adjust auto-save inhibitions accordingly. (allout-toggle-subtree-encryption): Adjust auto-save inhibition according to whether there are or aren't any plain-text topics pending encryption. (allout-inhibit-auto-save-info-for-decryption): Adjust buffer-saved-size and some allout state to inhibit auto-saves if there are plain-text topics pending encryption. (allout-maybe-resume-auto-save-info-after-encryption): Adjust buffer-saved-size and some allout state to not inhibit auto-saves if there are no longer any plain-text topics pending encryption. (allout-next-topic-pending-encryption), (allout-encrypt-decrypted): No longer provide for exemption of the current topic. --- lisp/ChangeLog | 46 +++++++++++ lisp/allout.el | 206 ++++++++++++++++++++++++++++--------------------- 2 files changed, 164 insertions(+), 88 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index d7def506d98..71fc929308b 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,49 @@ +2011-07-04 Ken Manheimer + + * allout.el (allout-encrypt-unencrypted-on-saves): Do not provide + insecure exception for current topic. Also note that auto-saves + are handled differently. + + (allout-auto-save-temporarily-disabled), (allout-just-did-undo): + State variables for tracking auto-save inhibition situation. + + (allout-write-contents-hook-handler): Rename from + 'allout-write-file-hook-handler', and describe how it depends on + write-contents-functions sensitivity to non-nil value to prevent + file write. + + (allout-auto-save-hook-handler): Remove. auto-save does not check + this in individual buffers, only in the starting buffer, so this + is not the right way for us to inhibit auto-save in a buffer + according to its condition. + + (allout-mode): Use new allout-write-contents-hook-handler, and + only with write-contents-functions. Remove auto-save provisions - + they're implemented elsewhere. + + (allout-before-change-handler): If undo is in progress, note that + for attention of allout-post-command-business. + + (allout-post-command-business): If the command we're following was + an undo, check for change in the status of encrypted items and + adjust auto-save inhibitions accordingly. + + (allout-toggle-subtree-encryption): Adjust auto-save inhibition + according to whether there are or aren't any plain-text topics + pending encryption. + + (allout-inhibit-auto-save-info-for-decryption): Adjust + buffer-saved-size and some allout state to inhibit auto-saves if + there are plain-text topics pending encryption. + + (allout-maybe-resume-auto-save-info-after-encryption): Adjust + buffer-saved-size and some allout state to not inhibit auto-saves + if there are no longer any plain-text topics pending encryption. + + (allout-next-topic-pending-encryption), + (allout-encrypt-decrypted): No longer provide for exemption of the + current topic. + 2011-07-04 Juri Linkov Add 7z operations to delete and save changed members (bug#8968). diff --git a/lisp/allout.el b/lisp/allout.el index d238745df17..5b8a7a7de1a 100644 --- a/lisp/allout.el +++ b/lisp/allout.el @@ -823,37 +823,32 @@ formatted copy." :group 'allout-encryption) ;;;_ = allout-encrypt-unencrypted-on-saves (defcustom allout-encrypt-unencrypted-on-saves t - "When saving, should topics pending encryption be encrypted? - -The idea is to prevent file-system exposure of any un-encrypted stuff, and -mostly covers both deliberate file writes and auto-saves. - - - Yes: encrypt all topics pending encryption, even if it's the one - currently being edited. (In that case, the currently edited topic - will be automatically decrypted before any user interaction, so they - can continue editing but the copy on the file system will be - encrypted.) - Auto-saves will use the \"All except current topic\" mode if this - one is selected, to avoid practical difficulties -- see below. - - All except current topic: skip the topic currently being edited, even if - it's pending encryption. This may expose the current topic on the - file sytem, but avoids the nuisance of prompts for the encryption - passphrase in the middle of editing for, eg, autosaves. - This mode is used for auto-saves for both this option and \"Yes\". - - No: leave it to the user to encrypt any unencrypted topics. - -For practical reasons, auto-saves always use the 'except-current policy -when auto-encryption is enabled. (Otherwise, spurious passphrase prompts -and unavoidable timing collisions are too disruptive.) If security for a -file requires that even the current topic is never auto-saved in the clear, -disable auto-saves for that file." - - :type '(choice (const :tag "Yes" t) - (const :tag "All except current topic" except-current) - (const :tag "No" nil)) - :version "22.1" + "If non-nil, topics pending encryption are encrypted during buffer saves. + +This provents file-system exposure of un-encrypted contents of +items marked for encryption. + +When non-nil, if the topic currently being edited is decrypted, +it will be encrypted for saving but automatically decrypted +before any subsequent user interaction, so it is once again clear +text for editing though the file system copy is encrypted. + +\(Auto-saves are handled differently. Buffers with plain-text +exposed encrypted topics are exempted from auto saves until all +such topics are encrypted.)" + + :type 'boolean + :version "23.1" :group 'allout-encryption) (make-variable-buffer-local 'allout-encrypt-unencrypted-on-saves) +(defvar allout-auto-save-temporarily-disabled nil + "True while topic encryption is pending and auto-saving was active. + +The value of buffer-saved-size at the time of decryption is used, +for restoring when all encryptions are established.") +(defvar allout-just-did-undo nil + "True just after undo commands, until allout-post-command-business.") +(make-variable-buffer-local 'allout-just-did-undo) ;;;_ + Developer ;;;_ = allout-developer group @@ -1564,39 +1559,43 @@ See `allout-encryption-ciphertext-rejection-regexps' for rejection reasons.") (defmacro allout-mode-p () "Return t if `allout-mode' is active in current buffer." 'allout-mode) -;;;_ > allout-write-file-hook-handler () -(defun allout-write-file-hook-handler () - "Implement `allout-encrypt-unencrypted-on-saves' policy for file writes." +;;;_ > allout-write-contents-hook-handler () +(defun allout-write-contents-hook-handler () + "Implement `allout-encrypt-unencrypted-on-saves' for file writes + +Return nil if all goes smoothly, or else return an informative +message if an error is encountered. The message will serve as a +non-nil return on `write-contents-functions' to prevent saving of +the buffer while it has decrypted content. + +This behavior depends on emacs versions that implement the +`write-contents-functions' hook." (if (or (not (allout-mode-p)) (not (boundp 'allout-encrypt-unencrypted-on-saves)) (not allout-encrypt-unencrypted-on-saves)) nil - (let ((except-mark (and (equal allout-encrypt-unencrypted-on-saves - 'except-current) - (point-marker)))) - (if (save-excursion (goto-char (point-min)) - (allout-next-topic-pending-encryption except-mark)) - (progn - (message "auto-encrypting pending topics") - (sit-for 0) - (condition-case failure + (if (save-excursion (goto-char (point-min)) + (allout-next-topic-pending-encryption)) + (progn + (message "auto-encrypting pending topics") + (sit-for 0) + (condition-case failure + (progn (setq allout-after-save-decrypt - (allout-encrypt-decrypted except-mark)) - (error (message - "allout-write-file-hook-handler suppressing error %s" - failure) - (sit-for 2))))) - )) - nil) -;;;_ > allout-auto-save-hook-handler () -(defun allout-auto-save-hook-handler () - "Implement `allout-encrypt-unencrypted-on-saves' policy for auto save." - - (if (and (allout-mode-p) allout-encrypt-unencrypted-on-saves) - ;; Always implement 'except-current policy when enabled. - (let ((allout-encrypt-unencrypted-on-saves 'except-current)) - (allout-write-file-hook-handler)))) + (allout-encrypt-decrypted)) + ;; aok - return nil: + nil) + (error + ;; whoops - probably some still-decrypted items, return non-nil: + (let ((text (format (concat "%s contents write inhibited due to" + " encrypted topic encryption error:" + " %s") + (buffer-name (current-buffer)) + failure))) + (message text)(sit-for 2) + text))))) + )) ;;;_ > allout-after-saves-handler () (defun allout-after-saves-handler () "Decrypt topic encrypted for save, if it's currently being edited. @@ -1960,12 +1959,7 @@ OPEN: A TOPIC that is not CLOSED, though its OFFSPRING or BODY may be." :lighter " Allout" :keymap 'allout-mode-map - (let ((write-file-hook-var-name (cond ((boundp 'write-file-functions) - 'write-file-functions) - ((boundp 'write-file-hooks) - 'write-file-hooks) - (t 'local-write-file-hooks))) - (use-layout (if (listp allout-layout) + (let ((use-layout (if (listp allout-layout) allout-layout allout-default-layout))) @@ -1984,9 +1978,8 @@ OPEN: A TOPIC that is not CLOSED, though its OFFSPRING or BODY may be." (remove-hook 'post-command-hook 'allout-post-command-business t) (remove-hook 'before-change-functions 'allout-before-change-handler t) (remove-hook 'isearch-mode-end-hook 'allout-isearch-end-handler t) - (remove-hook write-file-hook-var-name - 'allout-write-file-hook-handler t) - (remove-hook 'auto-save-hook 'allout-auto-save-hook-handler t) + (remove-hook 'write-contents-functions + 'allout-write-contents-hook-handler t) (remove-overlays (point-min) (point-max) 'category 'allout-exposure-category)) @@ -2019,9 +2012,8 @@ OPEN: A TOPIC that is not CLOSED, though its OFFSPRING or BODY may be." (add-hook 'post-command-hook 'allout-post-command-business nil t) (add-hook 'before-change-functions 'allout-before-change-handler nil t) (add-hook 'isearch-mode-end-hook 'allout-isearch-end-handler nil t) - (add-hook write-file-hook-var-name 'allout-write-file-hook-handler + (add-hook 'write-contents-functions 'allout-write-contents-hook-handler nil t) - (add-hook 'auto-save-hook 'allout-auto-save-hook-handler nil t) ;; Stash auto-fill settings and adjust so custom allout auto-fill ;; func will be used if auto-fill is active or activated. (The @@ -2154,8 +2146,10 @@ internal functions use this feature cohesively bunch changes." See `allout-overlay-interior-modification-handler' for details." - (when (and (allout-mode-p) undo-in-progress (allout-hidden-p)) - (allout-show-children)) + (when (and (allout-mode-p) undo-in-progress) + (setq allout-just-did-undo t) + (if (allout-hidden-p) + (allout-show-children))) ;; allout-overlay-interior-modification-handler on an overlay handles ;; this in other emacs, via `allout-exposure-category's 'modification-hooks. @@ -3308,12 +3302,29 @@ coordinating with allout activity.") - Implement (and clear) `allout-post-goto-bullet', for hot-spot outline commands. +- If the command we're following was an undo, check for change in + the status of encrypted items and adjust auto-save inhibitions + accordingly. + - Decrypt topic currently being edited if it was encrypted for a save." - ; Apply any external change func: (if (not (allout-mode-p)) ; In allout-mode. nil + (when allout-just-did-undo + (setq allout-just-did-undo nil) + (cond ((and (= buffer-saved-size -1) + allout-auto-save-temporarily-disabled) + ;; user possibly undid a decryption, deinhibit auto-save: + (allout-maybe-resume-auto-save-info-after-encryption)) + ((save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (not (allout-next-topic-pending-encryption)))) + ;; plain-text encrypted items are present, inhibit auto-save: + (allout-inhibit-auto-save-info-for-decryption (buffer-size))))) + (if (and (boundp 'allout-after-save-decrypt) allout-after-save-decrypt) (allout-after-saves-handler)) @@ -5899,6 +5910,8 @@ See `allout-toggle-current-subtree-encryption' for more details." " shift it in to make it encryptable"))) (let* ((allout-buffer (current-buffer)) + ;; for use with allout-auto-save-temporarily-disabled, if necessary: + (was-buffer-saved-size buffer-saved-size) ;; Assess location: (bullet-pos allout-recent-prefix-beginning) (after-bullet-pos (point)) @@ -5978,6 +5991,12 @@ See `allout-toggle-current-subtree-encryption' for more details." ;; Add the is-encrypted bullet qualifier: (goto-char after-bullet-pos) (insert "*")))) + + ;; adjust buffer's auto-save eligibility: + (if was-encrypted + (allout-inhibit-auto-save-info-for-decryption was-buffer-saved-size) + (allout-maybe-resume-auto-save-info-after-encryption)) + (run-hook-with-args 'allout-structure-added-hook bullet-pos subtree-end)))) ;;;_ > allout-encrypt-string (text decrypt allout-buffer keymode-cue @@ -6029,6 +6048,7 @@ signal." (epg-context-set-passphrase-callback context #'epa-passphrase-callback-function) context)) + (encoding (with-current-buffer allout-buffer buffer-file-coding-system)) (multibyte (with-current-buffer allout-buffer @@ -6150,8 +6170,29 @@ signal." result-text)) (error (concat "Encryption produced non-armored text, which" "conflicts with allout mode -- reconfigure!"))) - (t result-text)))) +;;;_ > allout-inhibit-auto-save-info-for-decryption +(defun allout-inhibit-auto-save-info-for-decryption (was-buffer-saved-size) + "Temporarily prevent auto-saves in this buffer when an item is decrypted. + +WAS-BUFFER-SAVED-SIZE is the value of buffer-saved-size *before* +the decryption." + (when (not (or (= buffer-saved-size -1) (= was-buffer-saved-size -1))) + (setq allout-auto-save-temporarily-disabled was-buffer-saved-size + buffer-saved-size -1))) +;;;_ > allout-maybe-resume-auto-save-info-after-encryption () +(defun allout-maybe-resume-auto-save-info-after-encryption () + "Restore auto-save info, *if* there are no topics pending encryption." + (when (and allout-auto-save-temporarily-disabled + (= buffer-saved-size -1) + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (not (allout-next-topic-pending-encryption))))) + (setq buffer-saved-size allout-auto-save-temporarily-disabled + allout-auto-save-temporarily-disabled nil))) + ;;;_ > allout-encrypted-topic-p () (defun allout-encrypted-topic-p () "True if the current topic is encryptable and encrypted." @@ -6162,14 +6203,10 @@ signal." (save-match-data (looking-at "\\*"))) ) ) -;;;_ > allout-next-topic-pending-encryption (&optional except-mark) -(defun allout-next-topic-pending-encryption (&optional except-mark) +;;;_ > allout-next-topic-pending-encryption () +(defun allout-next-topic-pending-encryption () "Return the point of the next topic pending encryption, or nil if none. -EXCEPT-MARK identifies a point whose containing topics should be excluded -from encryption. This supports 'except-current mode of -`allout-encrypt-unencrypted-on-saves'. - Such a topic has the `allout-topic-encryption-bullet' without an immediately following '*' that would mark the topic as being encrypted. It must also have content." @@ -6204,10 +6241,7 @@ must also have content." (setq content-beg (point)) (backward-char 1) (allout-end-of-subtree) - (if (or (<= (point) content-beg) - (and except-mark - (<= content-beg except-mark) - (>= (point) except-mark))) + (if (<= (point) content-beg) ;; Continue looking (setq got nil) ;; Got it! @@ -6219,14 +6253,10 @@ must also have content." ) ) ) -;;;_ > allout-encrypt-decrypted (&optional except-mark) -(defun allout-encrypt-decrypted (&optional except-mark) +;;;_ > allout-encrypt-decrypted () +(defun allout-encrypt-decrypted () "Encrypt topics pending encryption except those containing exemption point. -EXCEPT-MARK identifies a point whose containing topics should be excluded -from encryption. This supports the `except-current' mode of -`allout-encrypt-unencrypted-on-saves'. - If a topic that is currently being edited was encrypted, we return a list containing the location of the topic and the location of the cursor just before the topic was encrypted. This can be used, eg, to decrypt the topic @@ -6242,7 +6272,7 @@ save. See `allout-encrypt-unencrypted-on-saves' for more info." bo-subtree editing-topic editing-point) (goto-char (point-min)) - (while (allout-next-topic-pending-encryption except-mark) + (while (allout-next-topic-pending-encryption) (setq was-modified (buffer-modified-p)) (when (save-excursion (and (boundp 'allout-encrypt-unencrypted-on-saves) -- 2.39.2