Adds automatic update checks, schema-driven attribute and object-class editing,
and a more consistent interface. It also makes binary writes and DIT tree
expansion reliable, verifies update downloads, and recovers saved connections
from a backup.
Added
Automatic update checks. The app checks the latest GitLab release at startup
and every hour. The first time a newer release is found, it opens the update
dialog with the release notes; a badge in the header keeps that version
reachable after the dialog is closed. Choosing Update now downloads the
installer for the current platform, verifies its SHA-256 checksum, replaces
the app and restarts it.
Add Attribute guided by the schema. The picker offers only the attributes
the entry can still gain — MUST and MAY attributes from its object classes,
with aliases collapsed and excluding the RDN, read-only, password,
password-history and already-present single-valued attributes. The value
editor follows the attribute type: TRUE/FALSE, a calendar using the schema’s
timestamp format, a multi-line address field, or a file picker for binary,
image and certificate values. When the server schema is unavailable, the
dialog falls back to free-text entry.
Add Object Class. The editor can add the auxiliary object classes declared
by the server schema — the only kind an existing entry can gain — and leaves
out the classes the entry already carries. Without a schema, the field falls
back to free text.
Clear the Activity Log. A clear action in the Activity Log header empties
the log.
Empty panels explain themselves. A panel with nothing to show displays a
centred icon and message instead of an empty list.
Changed
One panel header. Connections, DIT, Activity Log and Search share the same
title-bar height and padding; the Search form sits below its title, and the
actions keep the same spacing across panels.
Consistent controls. Buttons, icon buttons, inputs and selects now have
consistent sizing, focus and hover behaviour.
Native platform font. The app no longer bundles Inter; it uses the
platform’s UI font, so no webfont is served and text matches the system.
Attribute edits wait for the server. Attribute additions and removals
appear only after the server accepts the write; a refusal leaves the entry
unchanged and shows the server’s message. New attributes are inserted in
alphabetical order.
Escape closes overlays. Escape now closes dialogs, selects and menus.
Windows support removed. Windows is no longer supported or packaged;
Linux and macOS remain supported.
Fixed
Binary attribute writes. Removing userCertificate or another
binary-transfer attribute no longer fails with LDAP code 17: ;binary is sent
only for the syntaxes that require it, on every write, including deletes, and
base64 values are decoded to their bytes.
A DIT node with children stays expandable. A node whose children are
already in memory keeps its arrow even when the schema hint calls it a leaf
and a later child fetch fails, so its rows stay reachable.
Corrupt connections are recovered. If the connections file is corrupt, the
app reads the owner-only .bak file instead of losing the saved connections.
The Linux AppImage has the correct icon. Cross-built AppImages now embed
the application icon.
More stable layout. Line heights and the heights of form fields are now
fixed and the monospace font is consistent, so the layout no longer depends
on how the rendering engine rounds line heights or measures the monospace
font. Labels, panels and buttons no longer shift by 1–2 px or truncate text
differently. Attribute values line up with their icons and timestamps with
the calendar icon; password dots are unchanged. Small character-width
differences remain, visible only when text is close to being cut off.
Security
Verified updates. The installer’s SHA-256 checksum is verified before an
update is applied, and an update without a published checksum is not offered.
TLS verification is visible. The connection form warns when certificate
verification is disabled, and a live TLS connection with it off carries a
persistent TLS off badge.
Safe release notes. The update dialog renders release notes with a minimal
Markdown renderer that escapes raw HTML and keeps unsafe links as plain text.
Performance
Add Attribute stays local. The picker is computed from the entry’s object
classes and the schema already in memory, with no extra LDAP round-trip.
Previous versions
▸v0.2.3
Makes the entry editor safer and more readable: multi-line values edit in
full, removals ask for confirmation, timestamps are edited with a calendar, and
narrow windows stay readable. Writes respect the server’s schema again.
Added
A calendar for timestamps. Timestamp attributes (createTimestamp,
modifyTimestamp, pwdLastSet and the other FILETIME values) are no longer
edited as raw strings: the editor opens a date/time picker, shows the value
in its human form, and writes it back in the attribute’s own format —
GeneralizedTime or FILETIME. The special FILETIME sentinels (never expires,
must change password, never logged on) are offered as their own action,
instead of being typed by hand.
Confirmation before removal. Removing a value or a whole attribute asks
for confirmation and shows the value being removed. The entry DN is no longer
a row among the attributes: it is shown in the editor’s header, where it
cannot be mistaken for a removable value.
Changed
Multi-line values edit in full. Editing a value used to cut it at the
first line; the editor now keeps the value’s lines exactly as displayed, so
long values can be read and changed in full.
The entry stays readable on narrow windows. When the window is narrow, an
attribute’s name and its badges stay on their own line and the values move
below them, instead of squeezing every column.
pwdHistory shows change dates. A password history value is recognized
by its record shape and shown as the date of the change — not as an opaque
binary value — whether or not the server’s schema classifies it as bytes.
Dropdowns centre the selected option when they open, so the current value
stays visible even in a long list.
The interface ships its own font. Text now renders with Inter instead of
the installed system font, so the app looks the same on every platform and
nothing wraps or truncates differently from one machine to another.
Fixed
Modifies no longer carry read-only operational attributes. An edit could
include an attribute the schema marks NO-USER-MODIFICATION, and the server
refused the whole operation (result code 19); such attributes are now never
written.
The last required value is protected. The editor no longer offers removing
the last value of an attribute the entry’s object classes require: the server
refuses it (result code 65) and the value belongs to the entry’s identity.
A refused change reloads the entry in order. When the server rejects an
edit, the restored attribute returns to its alphabetical position instead of
reappearing at the bottom of the list.
▸v0.2.2
Rewrites LDIF parsing and DN comparison, hardens the connection lifecycle, adds
password management for Active Directory, and narrows the desktop package’s
permissions.
Added
Passwords on Active Directory. Changing a password now works on AD, which
keeps it in a different attribute (unicodePwd) that is only writable over a
secure channel; the dialog adapts to the server, offering the hash algorithm on
OpenLDAP and warning about TLS on AD.
Attribute kinds from the schema. GUIDs, addresses, UUIDs, X.509
certificates, booleans and timestamps are now shown in their own form — a GUID
as a GUID, a boolean as true or false — instead of as the raw string.
Image thumbnails. Attributes that hold an image (jpegPhoto,
thumbnailPhoto) show a preview that opens full size, rather than base64.
Operational attributes. Reads now request the operational attributes as
well (* plus +), so pwdHistory and other operational values are visible;
a read-only attribute is marked from its NO-USER-MODIFICATION flag.
A warning banner in the edit form when the connection is open: only its
name can be changed then, because the running session keeps using the saved
configuration.
Changed
LDIF import and export conform to RFC 2849. The parser is a tokenizer
rather than a line loop, so folded lines, comments, :< URL values and
moddn/modrdn are handled correctly. An import is now all-or-nothing (a file
with one error applies nothing) and reports the outcome per record; export
base64-encodes non-SAFE values and folds at 76 columns, staying re-importable.
An edit is written as soon as it is made, one write at a time, instead of
waiting for a 600 ms quiet period. There is no pending window left to drop, so
moving to another entry right after an edit no longer loses it, and a write
that finishes after the panel moved on no longer touches it.
DNs are compared and keyed in their RFC 4514 normalized form, so two DNs
that denote the same entry but are written differently — extra spaces, escape
style, or the order of a multi-valued RDN — are treated as the same.
Clicking a connection that is already open makes it active instead of
reconnecting it, so it no longer flashes “connecting” for nothing.
userPassword is no longer treated as binary on a stock OpenLDAP server,
so the password attribute is shown and edited as text.
Binary values read more clearly and the attribute name and value columns
line up.
Fixed
A failed reconnect keeps your session. Reconnecting used to drop the old
client before binding the new one, so a wrong password or a server briefly down
left you disconnected; the new client is now bound first and the old one
replaced only on success.
Closing the app closes its sessions with an unbind, instead of leaving the
server to reap them.
A session whose credentials were refused is ended, instead of staying shown
as connected while every operation fails.
Two connects at once can no longer open two sockets, and a double click no
longer starts a second one.
Deleting an entry no longer lets it reappear: a fetch that was already in
flight when the entry was deleted is no longer reused or injected.
The connection list and a search index can no longer be left stale by an
aborted build or a deletion that arrives while a fetch is running.
The connection import works in the desktop app: the file picker now hands
the chosen file to an input that is part of the document.
Search This Branch always starts. The search panel applied a branch search
requested from the tree only when the selection happened to change; it now
reacts to the request itself, so the search runs even with the selection still.
The tree refreshes and reveals when another panel asks. An import, a rename
or a search result now updates the tree at once, instead of waiting for an
unrelated render.
Security
The desktop package asks for fewer permissions: the local HTTP server and
the LDAP connections, the connections file, and the environment variables that
pick its directory — not the whole -A.
▸v0.2.1
Fixes a fault that made wide searches return a fraction of their entries while
reporting success. Also fixes losing your edits when a save is refused, losing
them again when the server had dropped an idle connection, and an auto-save that
could send values you had already changed.
Fixed
Searches no longer report success on an incomplete result. Wide searches
had been failing on the packaged app since 0.2.0, where the symptom was a
crash; the release mitigated it by capping pages at 850 entries, which held
often enough to ship but left the cause unidentified. That cause has now been
measured. The message parser in ldapts, the LDAP library, calls itself once
per message that arrives in the same TCP read, so the stack depth was set by
how the network happened to deliver the response rather than by anything the
app requested, and the packaged app runs on QuickJS, whose stack holds an
order of magnitude fewer of those calls than the V8 engine the dev server
uses. Past the limit the overflow was swallowed and the entries already parsed
were returned as if complete, which is the more damaging form of the same
fault: a crash is at least visible. Incoming data is now reassembled into one
message per read before the parser sees it, so the depth is fixed at one call
regardless of how the response arrives. The measurements, and the two
explanations they ruled out, are written up in
FRAMING.md.
A refused save no longer discards your work. When the directory rejected
an attribute, the value stayed in the local entry and every later save
resubmitted it and failed again, even for an unrelated edit. If the edit
included the entry’s name, the rename committed while the rest did not,
leaving the app pointing at a DN the directory no longer knew.
An idle connection repairs itself. After a period of inactivity the app
still showed itself connected while the server had closed the connection: the
next operation failed, the session was torn down, and the current selection
and any unsaved edit went with it. The connection is now checked before use
and rebound when needed, without asking for credentials again.
Auto-save cannot send values you have already changed. A pending save is
cancelled when the entry changes, when the connection goes away, before a
delete and after a refusal, and two saves can no longer overlap.
Write errors name the operation and the result code instead of the hex
suffix the library appends.
Group ranges in the tree are bracketed ([1...250]), so a range no longer
reads as an entry named after it.
Changed
Pages of a search or a branch enumeration carry 1500 entries instead of 850.
The 850 cap was a mitigation, not a setting: it kept the parser under its
limit often enough to work, on the working assumption that the page size
governed the recursion depth. Measurement showed it does not — what governs
the depth is how many messages share one TCP read, which no page size
controls. With the cause addressed, the page size only trades round trips
against the memory one page holds. Enumerating 21 000 entries takes 14 pages
instead of 25; the cost of parsing each entry is unchanged.
▸v0.2.0
Makes large directories usable: branches and search results with tens of
thousands of entries are paged instead of fetched whole, and attributes are
rendered from the server schema, so timestamps are readable and read-only
attributes are marked. Side panels collapse and resize. Fixes binary value
corruption on save and several LDIF parsing errors.
Added
The connection form can look up the available base DNs from the server’s Root
DSE, instead of requiring them to be typed in.
Side panels can be collapsed and resized by dragging; dragging past the
minimum width collapses the panel, and double clicking the resize grip
restores the default width.
Large branches of the tree are shown as position ranges (1...250) and only
the open range is fetched.
A branch with more children than the index holds is now marked as capped,
with a tooltip naming the limit, and its context menu offers Search This
Branch to reach the rest through the search panel.
Non-editable attributes carry a read-only hint.
Timestamp attributes (GeneralizedTime and Active Directory FILETIME) are
formatted for humans.
Changed
How an attribute is displayed and whether it can be edited now comes from the
server subschema rather than a built-in list, so the app follows the
directory’s own definitions.
Search results are paged through a sorted index built once per query: showing
ten matches no longer fetches all of them. Indexing runs on a second
connection, so a search never stalls the tree.
Error messages describe the LDAP result code instead of showing its hex value
(No such object (code 32) in place of Code: 0x20).
Long attribute names are revealed on hover, and the name column is wider.
Scrollbars follow the platform’s overlay style.
Fixed
Values the directory returns as raw bytes are written back unchanged. Saving
an entry with a binary attribute previously corrupted it.
LDIF import read a folded dn: line as its last segment only, and merged
consecutive modify records into the first.
Two paged operations on the same connection made the server reject one of
them with unwillingToPerform (0x35).
Pressing Next twice in the search results skipped a page, and paging or
exporting after editing a search field applied the new criteria to the old
result set.
Context menu actions could act on the wrong node when the menu had been
reopened elsewhere.
The LDIF export log reported the size of the index rather than the number of
entries exported.
Loading spinners wobbled instead of turning in place in the desktop app.
Long attribute values wrap instead of scrolling the pane sideways, the remove
cross no longer reflows the value next to it, and attribute names and
read-only values can be selected.
▸v0.1.1
Adds StartTLS connections, decouples saving a connection from testing it, and
closes modals only on explicit actions. Fixes the desktop window close and size.
Added
StartTLS protocol for connections, alongside LDAP and LDAPS.
Changed
A connection can now be saved without a successful test, so a profile can be
stored with incomplete credentials and completed later.
Modals no longer close when clicking outside; they close only via their close
button or the Escape key.
Fixed
Closing the application window now terminates the process.
The application window now opens at a fixed size (1200×800).
▸v0.1.0
Initial release of Dirdap, a desktop app to browse, search and edit LDAP
directories locally. Available for Linux, macOS and Windows.
Added
Create, test and manage LDAP and LDAPS connection profiles, with export and
import.
Browse the directory information tree, with a per-entry context menu (copy,
paste, delete, LDIF export/import).
Read, add, modify and delete entries and attributes, with inline editing and
auto-save.
Scoped search (base, one level, subtree) with paginated results and LDIF
export.
Import and export LDIF, plus a standalone LDIF editor.
Verify and change user passwords, hashed with RFC 2307.
Activity log for every operation.
Security
Binds to localhost only, with CSRF protection and hardened response headers.
LDIF export warns that connection passwords are exported in plain text.