{"id":"691677ceadcd0bfee0251eef","title":"2025 11 08 Issue 80","path":"how-to/committee/release-notes/2025-11-08-issue-80","contentMarkdown":"# 8th November 2025 — Config Security and Secret Input UX [#80](https://github.com/nbarrett/ngx-ramblers/issues/80)\n## [build 356](https://github.com/nbarrett/ngx-ramblers/actions/runs/19226914031) — [Refs: #80](https://github.com/nbarrett/ngx-ramblers/issues/80) — [commit a402a28](https://github.com/nbarrett/ngx-ramblers/commit/a402a28)\n\nPrevent sensitive data loss during config saves and improve secret input UX with tooltips and proper sizing.\n\n**Where to Find It**\n\n- **Settings**: All configuration forms with sensitive fields\n- **OS Maps API Key**: Secret input with show/hide and copy buttons\n- **Mail API Configuration**: Secure key input with tooltips\n\n**Benefits**\n\n- **Data Protection**: Sensitive fields restored from database when missing from save payload\n- **Admin-Only Access**: 403 response for non-admins attempting config updates\n- **Better UX**: Secret input components sized to match vanilla inputs\n- **Helpful Tooltips**: Show/hide and copy buttons have 500ms delay tooltips\n- **Cleaner Code**: ES-Toolkit functions replace typeof checks (isObject, isArray, isString, isNumber, isFunction)\n- **DRY Principle**: Sensitive field handling centralized in module constant\n\n**Technical Details**\n\nBackend Security:\n- Add restoreSensitiveFields() to merge missing sensitive fields from existing DB record\n- Distinguish missing fields (redacted) vs explicitly cleared fields (empty/null) using 'in' operator\n- Add admin-only access check for config updates (403 for non-admins)\n- Extract sensitiveKeys Set to module constant for DRY code\n- Sensitive fields protected: apiKey, accessKeyId, secretAccessKey, clientSecret, accessToken, refreshToken, password, username, userName\n\nFrontend Secret Input:\n- Replace plain text inputs with secret-input component for OS Maps and Mail API keys\n- Fix sizing: use input-sm class to match vanilla inputs\n- Add ngx-bootstrap tooltips to show/hide and copy buttons with 500ms delay\n- Add size=\"sm\" attribute to secret-input usages\n\nCode Quality:\n- Replace typeof checks with ES-Toolkit functions across server and frontend\n- isObject, isArray, isString, isNumber, isFunction used consistently\n- Apply DRY principle to sensitive field handling in config.ts\n\nUI Polish:\n- Style Row Actions section with thumbnail-heading-frame to match individual Row frames\n- Consistent visual treatment across configuration UI","contentHtml":"<h1>8th November 2025 — Config Security and Secret Input UX <a href=\"https://github.com/nbarrett/ngx-ramblers/issues/80\">#80</a></h1>\n<h2><a href=\"https://github.com/nbarrett/ngx-ramblers/actions/runs/19226914031\">build 356</a> — <a href=\"https://github.com/nbarrett/ngx-ramblers/issues/80\">Refs: #80</a> — <a href=\"https://github.com/nbarrett/ngx-ramblers/commit/a402a28\">commit a402a28</a></h2>\n<p>Prevent sensitive data loss during config saves and improve secret input UX with tooltips and proper sizing.</p>\n<p><strong>Where to Find It</strong></p>\n<ul>\n<li><strong>Settings</strong>: All configuration forms with sensitive fields</li>\n<li><strong>OS Maps API Key</strong>: Secret input with show/hide and copy buttons</li>\n<li><strong>Mail API Configuration</strong>: Secure key input with tooltips</li>\n</ul>\n<p><strong>Benefits</strong></p>\n<ul>\n<li><strong>Data Protection</strong>: Sensitive fields restored from database when missing from save payload</li>\n<li><strong>Admin-Only Access</strong>: 403 response for non-admins attempting config updates</li>\n<li><strong>Better UX</strong>: Secret input components sized to match vanilla inputs</li>\n<li><strong>Helpful Tooltips</strong>: Show/hide and copy buttons have 500ms delay tooltips</li>\n<li><strong>Cleaner Code</strong>: ES-Toolkit functions replace typeof checks (isObject, isArray, isString, isNumber, isFunction)</li>\n<li><strong>DRY Principle</strong>: Sensitive field handling centralized in module constant</li>\n</ul>\n<p><strong>Technical Details</strong></p>\n<p>Backend Security:</p>\n<ul>\n<li>Add restoreSensitiveFields() to merge missing sensitive fields from existing DB record</li>\n<li>Distinguish missing fields (redacted) vs explicitly cleared fields (empty/null) using &#39;in&#39; operator</li>\n<li>Add admin-only access check for config updates (403 for non-admins)</li>\n<li>Extract sensitiveKeys Set to module constant for DRY code</li>\n<li>Sensitive fields protected: apiKey, accessKeyId, secretAccessKey, clientSecret, accessToken, refreshToken, password, username, userName</li>\n</ul>\n<p>Frontend Secret Input:</p>\n<ul>\n<li>Replace plain text inputs with secret-input component for OS Maps and Mail API keys</li>\n<li>Fix sizing: use input-sm class to match vanilla inputs</li>\n<li>Add ngx-bootstrap tooltips to show/hide and copy buttons with 500ms delay</li>\n<li>Add size=&quot;sm&quot; attribute to secret-input usages</li>\n</ul>\n<p>Code Quality:</p>\n<ul>\n<li>Replace typeof checks with ES-Toolkit functions across server and frontend</li>\n<li>isObject, isArray, isString, isNumber, isFunction used consistently</li>\n<li>Apply DRY principle to sensitive field handling in config.ts</li>\n</ul>\n<p>UI Polish:</p>\n<ul>\n<li>Style Row Actions section with thumbnail-heading-frame to match individual Row frames</li>\n<li>Consistent visual treatment across configuration UI</li>\n</ul>\n"}