1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
|
#+TITLE: Emacs Simple Bookmark
#+AUTHOR: 0xhenrique
#+DATE: 2025
* Overview
This is a simple encrypted bookmark manager for Emacs that stores bookmarks in an encrypted file suitable for syncing via Git. It uses GPG encryption to keep your bookmarks secure while allowing you to store them in public repositories.
This README has become quite extensive, but I hope it addresses most of the doubts that may arise regarding its usage or potential issues that may occur. Nonetheless, please do not hesitate to open an issue if you encounter any problems. Pull requests are always welcome as well.
* Features
- Encrypted bookmark storage using GPG (with plain text option)
- Simple JSON format
- Git-friendly
- Built-in Emacs integration
- Tag support
- Filtering by tags
- No external dependencies beyond GPG (you probably already have that)
* Installation and Setup
** 1. GPG Configuration
*** Check if GPG is installed
#+BEGIN_SRC bash
gpg --version
#+END_SRC
If GPG is not installed... Install it!
*** Generate a GPG key (if you don't have one)
#+BEGIN_SRC bash
gpg --full-generate-key
#+END_SRC
Choose the following options:
1. RSA and RSA (default)
2. 4096 bits (recommended for long-term use)
3. Key validity (0 = no expiration, or set as preferred)
4. Enter name and email address
5. Set a strong passphrase
*** Verify if your key was created
#+BEGIN_SRC bash
gpg --list-secret-keys --keyid-format LONG
#+END_SRC
** 2. Emacs Configuration
*** Basic setup
Add to your Emacs configuration:
#+BEGIN_SRC elisp
;; Load esb.el (if not installing via package manager)
(load-file "~/path/to/esb.el")
;; Optional: customize bookmark file location
(setq esb-bookmarks-file "~/bookmarks/bookmarks.gpg")
;; Optional: use plain text instead of GPG encryption
;; (setq esb-storage-backend 'plain)
#+END_SRC
*** Asymmetric vs Symmetric Encryption
By default, ESB uses symmetric encryption (passphrase only). If you want asymmetric encryption tied to your GPG key:
#+BEGIN_SRC elisp
(setq esb-gpg-recipient "[email protected]") ; or GPG key ID
#+END_SRC
If you already have a symmetrically encrypted file, reload and save to re-encrypt:
#+BEGIN_SRC elisp
M-x esb-reload-bookmarks
M-x esb-add-bookmark ; or edit any bookmark to trigger save
#+END_SRC
To disable encryption entirely:
#+BEGIN_SRC elisp
(setq esb-storage-backend 'plain)
(setq esb-bookmarks-file "~/bookmarks/bookmarks.json")
#+END_SRC
*** Key Binding Setup
ESB doesn't define any global key bindings by default to avoid conflicts. You need to define your own key bindings.
**** Key bindings I use
#+BEGIN_SRC elisp
(global-set-key (kbd "C-c C-b s") 'esb-select-bookmark)
(global-set-key (kbd "C-c C-b a") 'esb-add-bookmark)
(global-set-key (kbd "C-c C-b d") 'esb-delete-bookmark)
(global-set-key (kbd "C-c C-b l") 'esb-list-bookmarks)
(global-set-key (kbd "C-c C-b e") 'esb-edit-bookmark)
(global-set-key (kbd "C-c C-b t") 'esb-list-tags)
(global-set-key (kbd "C-c C-b r") 'esb-reload-bookmarks)
(global-set-key (kbd "C-c C-b i") 'esb-initialize)
#+END_SRC
** 3. Git Repository Setup
*** Initialize bookmark repository
#+BEGIN_SRC bash
# Create directory for bookmarks
mkdir ~/bookmarks
cd ~/bookmarks
# Initialize git repository
git init
# Create .gitignore (optional - exclude temporary files)
echo "*~" > .gitignore
echo "*.bak" >> .gitignore
# Initial commit
git add .gitignore
git commit -m "your commit message"
#+END_SRC
*** Connect to GitHub
#+BEGIN_SRC bash
# Create repository on GitHub (or any provider you prefer) first, then:
git remote add origin [email protected]:yourusername/bookmarks.git
# Push initial commit
git push -u origin master
#+END_SRC
*** Configure bookmark file path
Update your Emacs config to point to the git repository:
#+BEGIN_SRC elisp
(setq esb-bookmarks-file "~/bookmarks/bookmarks.gpg")
#+END_SRC
* Usage
** Available Functions
All functions are autoloaded and can be called via ~M-x~:
- ~esb-select-bookmark~ - Select bookmark and copy URL to clipboard (prefix arg to filter by tag)
- ~esb-add-bookmark~ - Add new bookmark with URL, description and tags are optional
- ~esb-delete-bookmark~ - Delete bookmark by selection
- ~esb-list-bookmarks~ - Display all bookmarks in a buffer (prefix arg to filter by tag)
- ~esb-edit-bookmark~ - Edit bookmark description and tags
- ~esb-list-tags~ - Display all available tags with bookmark counts
- ~esb-reload-bookmarks~ - Reload bookmarks from file (after git pull)
- ~esb-initialize~ - Initialize empty bookmark file
** Tag Usage
*** Adding tags
When adding bookmarks, you can specify tags as comma-separated values:
- Single tag: ~work~
- Multiple tags: ~work, api, reference~
- Tags with spaces: ~machine learning, data science~
*** Filtering by tags
Use prefix argument (C-u) with list and select functions:
- ~C-u C-c C-b l~ - List bookmarks filtered by tag
- ~C-u C-c C-b s~ - Select bookmark filtered by tag
** Basic workflow
*** First time setup
1. ~M-x esb-initialize~ - Create empty encrypted bookmark file
2. ~M-x esb-add-bookmark~ - Add your first bookmark with tags
3. Commit and push to GitHub
*** Adding bookmarks with tags
#+BEGIN_EXAMPLE
M-x esb-add-bookmark
Bookmark URL: https://api.github.com
Description (optional): GitHub API Documentation
Tags (comma-separated, optional): work, api, reference
#+END_EXAMPLE
*** Syncing across machines
#+BEGIN_SRC bash
# Pull latest bookmarks
git pull
# In Emacs: reload bookmarks
M-x esb-reload-bookmarks
# After making changes: commit and push
git add bookmarks.gpg
git commit -m "your message"
git push
#+END_SRC
* Git Workflow
** Adding bookmarks
#+BEGIN_SRC bash
# After adding bookmarks in Emacs
git add bookmarks.gpg
git commit -m "add new bookmarks, etc..."
git push
#+END_SRC
** Syncing on different machines
#+BEGIN_SRC bash
# Pull latest changes
git pull
# Reload in Emacs
M-x esb-reload-bookmarks
#+END_SRC
Note: GPG files can't be automatically merged, so avoid simultaneous edits when possible.
* Security Considerations
** GPG Key Management
- Keep your private key secure and backed up (VERY IMPORTANT!)
- Use a strong passphrase for your GPG key (you can cache it)
- The same GPG key must be available on all machines where you use bookmarks
** Repository Security
- Your encrypted bookmark file is safe to store in public repositories
- The repository only contains the encrypted file, not plaintext bookmarks
** Best Practices
- Never commit your GPG private key to the repository (ALSO VERY IMPORTANT!)
- Regularly backup your GPG keys! (ALSO VERY IMPORTANT!)
* Configuration Options
** Customizable Variables
#+BEGIN_SRC elisp
;; Bookmark file location
(setq esb-bookmarks-file "~/path/to/bookmarks.gpg")
;; Storage backend (gpg, plain, or custom function)
(setq esb-storage-backend 'gpg) ; default: GPG encrypted
;; (setq esb-storage-backend 'plain) ; plain text
;; GPG program path (if needed)
(setq epg-gpg-program "/usr/local/bin/gpg")
;; Cache passphrase
(setq epa-file-cache-passphrase-for-symmetric-encryption t)
#+END_SRC
** Storage Backends
*** GPG (default)
Stores bookmarks in GPG-encrypted files, suitable for public repositories like Github.
*** Plain Text
Stores bookmarks in plain JSON files. Useful for local-only usage or when GPG is not available.
#+BEGIN_SRC elisp
(setq esb-storage-backend 'plain)
(setq esb-bookmarks-file "~/bookmarks/bookmarks.json")
#+END_SRC
* File Format
The encrypted file is just a simple JSON array:
#+BEGIN_SRC json
[
{
"url": "https://example.com",
"description": "Example website",
"tags": ["work", "reference"]
},
{
"url": "https://github.com",
"description": null,
"tags": ["code", "git"]
},
{
"url": "https://api.example.com",
"description": "API docs",
"tags": null
}
]
#+END_SRC
* Troubleshooting
** Key Binding Conflicts
If you encounter key binding conflicts:
1. Check what's currently bound: ~C-h k [key-sequence]~
2. Choose different keys for ESB functions
3. Use ~global-set-key~ to define exactly what you want
** GPG Issues
- Ensure GPG is properly configured and your key is available
- Check that ~epa-file~ is working: try opening any ~.gpg~ file
- Verify GPG agent is running if using GUI Emacs
** Invalid Bookmark Errors
ESB now validates bookmarks and will skip invalid entries:
- URLs must start with http:// or https://
- Tags must be strings if present
- Use ~M-x esb-reload-bookmarks~ if you manually edit the file (NOT RECOMMENDED!)
* License
This is a simple encrypted bookmark manager for Emacs that stores bookmarks in an encrypted file suitable for syncing via Git. It uses GPG encryption to keep your bookmarks secure while allowing you to store them in public repositories.
Copyright (C) 2025 0xhenrique
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|