feat: full IAM impersonation support — read-only + original user + canWrite

- src/auth.js: all impersonation fields + permissions.can_write
- src/routes/oidc.js: save all fields to session
- ui/index.js: canWrite, originalUserEmail in req.user
- ui/routes/entries.js: read-only guard on POST/PATCH/DELETE
- docs/PLAN-impersonation.md: updated with implemented items
This commit is contained in:
2026-06-11 15:54:56 +04:00
parent a2cfd2c10f
commit 9a331eec82
6 changed files with 38 additions and 2 deletions
+12
View File
@@ -185,6 +185,14 @@
<% if (typeof isImpersonated !== 'undefined' && isImpersonated) { %>
<div style="background:#fef3c7;border:1px solid #d97706;color:#92400e;padding:.5rem 1rem;border-radius:8px;margin-bottom:.5rem;font-size:.85rem;">
⚠️ Режим имперсонации — данные сохраняются от имени <strong><%= user.clientId %></strong>
<% if (typeof originalUserEmail !== 'undefined' && originalUserEmail) { %>
(вы: <%= originalUserEmail %>)
<% } %>
</div>
<% } %>
<% if (typeof canWrite !== 'undefined' && !canWrite) { %>
<div style="background:#fee2e2;border:1px solid #dc2626;color:#991b1b;padding:.5rem 1rem;border-radius:8px;margin-bottom:.5rem;font-size:.85rem;">
🔒 Режим только для чтения — редактирование запрещено
</div>
<% } %>
@@ -279,6 +287,7 @@
</div>
<!-- Форма добавления -->
<% if (typeof canWrite === 'undefined' || canWrite) { %>
<div class="card">
<div class="card-header">Добавить адрес</div>
<div class="card-body">
@@ -308,6 +317,7 @@
</form>
</div>
</div>
<% } %>
<!-- Таблица -->
<div class="card">
@@ -341,6 +351,7 @@
: '—' %>
</td>
<td class="text-center" style="white-space:nowrap;">
<% if (typeof canWrite === 'undefined' || canWrite) { %>
<%
// data-* атрибуты для JS-заполнения modal без inline-onclick с параметрами.
// Так как комментарий может содержать кавычки — EJS экранирует их в HTML.
@@ -365,6 +376,7 @@
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button class="btn btn-danger">Удалить</button>
</form>
<% } %>
</td>
</tr>
<% }) %>