Compare commits
1 Commits
fd0bf89e9e
..
0.1.3
| Author | SHA1 | Date | |
|---|---|---|---|
| f728d74f34 |
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
// 2) при успехе — trigger Deploy с wait:false и agent none → Builder-под умирает
|
// 2) при успехе — trigger Deploy с wait:false и agent none → Builder-под умирает
|
||||||
// 3) Deploy стартует отдельно уже без Builder
|
// 3) Deploy стартует отдельно уже без Builder
|
||||||
//
|
//
|
||||||
// Версия образа = VERSION из коммита (без auto-bump). Ручной bump: make bump-patch.
|
// Версия образа = VERSION из коммита. Bump: make bump-patch / make push.
|
||||||
//
|
//
|
||||||
// Credentials (Global):
|
// Credentials (Global):
|
||||||
// harbor-devops-tools-push-pull-access — Harbor devops-tools (robot)
|
// harbor-devops-tools-push-pull-access — Harbor devops-tools (robot)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ help:
|
|||||||
@echo " make bump-minor VERSION +0.1.0"
|
@echo " make bump-minor VERSION +0.1.0"
|
||||||
@echo " make release Multi-arch build & push $(FULL_IMAGE)"
|
@echo " make release Multi-arch build & push $(FULL_IMAGE)"
|
||||||
@echo " platforms: $(RELEASE_PLATFORMS)"
|
@echo " platforms: $(RELEASE_PLATFORMS)"
|
||||||
@echo " make push git add/commit (prompt) + push (без auto-bump)"
|
@echo " make push bump-patch + git add/commit (prompt) + push"
|
||||||
@echo " make helm-lint Lint Helm chart"
|
@echo " make helm-lint Lint Helm chart"
|
||||||
@echo " make helm-package Package Helm chart"
|
@echo " make helm-package Package Helm chart"
|
||||||
@echo " make clean Remove containers, volumes, local image"
|
@echo " make clean Remove containers, volumes, local image"
|
||||||
@@ -136,7 +136,7 @@ clean:
|
|||||||
-docker buildx rm $(BUILDX_BUILDER) 2>/dev/null || true
|
-docker buildx rm $(BUILDX_BUILDER) 2>/dev/null || true
|
||||||
rm -rf dist
|
rm -rf dist
|
||||||
|
|
||||||
# Ручной SemVer (не вызывается из make push).
|
# Same flow as proxmox_api_simulator / infra: bump SemVer, stage, multiline commit, push.
|
||||||
bump-patch:
|
bump-patch:
|
||||||
@PYTHONPATH=. python3 scripts/bump_version.py patch
|
@PYTHONPATH=. python3 scripts/bump_version.py patch
|
||||||
@echo "VERSION → $$(cat VERSION)"
|
@echo "VERSION → $$(cat VERSION)"
|
||||||
@@ -153,7 +153,7 @@ version-commit:
|
|||||||
git commit -m "Bump version to $$(cat VERSION)."; \
|
git commit -m "Bump version to $$(cat VERSION)."; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
push:
|
push: bump-patch
|
||||||
@set -e; \
|
@set -e; \
|
||||||
git add .; \
|
git add .; \
|
||||||
echo "=== staged ==="; \
|
echo "=== staged ==="; \
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ services:
|
|||||||
|
|
||||||
### UX (v0.1.3+)
|
### UX (v0.1.3+)
|
||||||
|
|
||||||
- После создания: **QR** на share-link, иконки **скачать QR (PNG)** и **Web Share** (если есть `navigator.share`) под QR; отдельные кнопки Copy для ссылки / токена / пароля; пароль не советуется слать в той же переписке.
|
- После создания: **QR** на share-link, **скачать QR (PNG)**, **Web Share** (если есть `navigator.share`), чеклист и trust-строка про `#key`; отдельные кнопки Copy для ссылки / токена / пароля; пароль не советуется слать в той же переписке.
|
||||||
- Create: счётчик размера `≈ used / max` и предупреждение near-limit (сверх лимита — `create.tooLarge`).
|
- Create: счётчик размера `≈ used / max` и предупреждение near-limit (сверх лимита — `create.tooLarge`).
|
||||||
- Unwrap: Enter в поле пароля отправляет форму; после `password_required` / `bad_password` — focus+select; при ≥2 элементах — **скачать всё** (zip через JSZip); trust-строка на результате; спокойный экран «ссылка недоступна» для already used / expired (anti-enumeration); отдельные состояния для `password_locked`, rate limit, CAPTCHA, ошибки расшифровки.
|
- Unwrap: Enter в поле пароля отправляет форму; после `password_required` / `bad_password` — focus+select; при ≥2 элементах — **скачать всё** (zip через JSZip); trust-строка на результате; спокойный экран «ссылка недоступна» для already used / expired (anti-enumeration); отдельные состояния для `password_locked`, rate limit, CAPTCHA, ошибки расшифровки.
|
||||||
- Картинки после unwrap: inline-превью и **lightbox** (тап/клик).
|
- Картинки после unwrap: inline-превью и **lightbox** (тап/клик).
|
||||||
@@ -452,8 +452,8 @@ docker buildx build \
|
|||||||
| Где | Поведение |
|
| Где | Поведение |
|
||||||
|-----|-----------|
|
|-----|-----------|
|
||||||
| UI (модалка «?») | бейдж `vX.Y.Z` |
|
| UI (модалка «?») | бейдж `vX.Y.Z` |
|
||||||
| `make bump-patch` / `bump-minor` | ручной bump (по желанию) |
|
| `make bump-patch` / `bump-minor` | ручной bump |
|
||||||
| `make push` | commit/push **без** auto-bump |
|
| `make push` | автоматически `bump-patch`, затем commit/push |
|
||||||
| Jenkins (`Jenkinsfile`) | читает `VERSION` из коммита **без** доп. bump → те же теги в образе и на кластере |
|
| Jenkins (`Jenkinsfile`) | читает `VERSION` из коммита **без** доп. bump → те же теги в образе и на кластере |
|
||||||
|
|
||||||
Что в `VERSION` запушили — то и уйдёт в Harbor/Hub/деплой (и в футер модалки внутри образа).
|
Что в `VERSION` запушили — то и уйдёт в Harbor/Hub/деплой (и в футер модалки внутри образа).
|
||||||
|
|||||||
+40
-56
@@ -322,6 +322,46 @@ html[data-theme="dark"] .icon-btn:hover {
|
|||||||
font-size: 0.84rem;
|
font-size: 0.84rem;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
.success-checklist {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: grid;
|
||||||
|
gap: 0.35rem;
|
||||||
|
}
|
||||||
|
.success-checklist li {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 1.35rem;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.success-checklist li::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0.35rem;
|
||||||
|
width: 0.55rem;
|
||||||
|
height: 0.55rem;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1.5px solid var(--accent-2);
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
.success-trust {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.84rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
.success-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 0.35rem;
|
||||||
|
}
|
||||||
|
.success-actions .btn {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 8rem;
|
||||||
|
}
|
||||||
.size-meter {
|
.size-meter {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
@@ -341,7 +381,6 @@ html[data-theme="dark"] .icon-btn:hover {
|
|||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: visible;
|
|
||||||
}
|
}
|
||||||
.share-qr {
|
.share-qr {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
@@ -366,61 +405,6 @@ html[data-theme="dark"] .icon-btn:hover {
|
|||||||
max-width: 11rem;
|
max-width: 11rem;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
}
|
}
|
||||||
.success-qr-actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 0.4rem;
|
|
||||||
margin-top: 0.15rem;
|
|
||||||
}
|
|
||||||
.qr-action-btn {
|
|
||||||
position: relative;
|
|
||||||
width: 2.35rem;
|
|
||||||
height: 2.35rem;
|
|
||||||
border: 1px solid var(--line);
|
|
||||||
border-radius: 10px;
|
|
||||||
background: transparent;
|
|
||||||
color: var(--muted);
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 0;
|
|
||||||
transition: color 0.15s, background 0.15s, border-color 0.15s;
|
|
||||||
}
|
|
||||||
.qr-action-btn:hover,
|
|
||||||
.qr-action-btn:focus-visible {
|
|
||||||
color: var(--accent-2);
|
|
||||||
background: rgba(75, 134, 240, 0.1);
|
|
||||||
border-color: rgba(75, 134, 240, 0.35);
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.qr-action-btn:active {
|
|
||||||
transform: scale(0.96);
|
|
||||||
}
|
|
||||||
.qr-action-btn .ui-tooltip {
|
|
||||||
left: 50%;
|
|
||||||
right: auto;
|
|
||||||
bottom: calc(100% + 0.5rem);
|
|
||||||
transform: translateX(-50%) translateY(4px);
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.qr-action-btn .ui-tooltip::after {
|
|
||||||
left: 50%;
|
|
||||||
right: auto;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
.qr-action-btn:hover .ui-tooltip,
|
|
||||||
.qr-action-btn:focus-visible .ui-tooltip {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
.success-panel > .expires-meta {
|
|
||||||
width: 100%;
|
|
||||||
justify-self: stretch;
|
|
||||||
margin-top: 0.15rem;
|
|
||||||
}
|
|
||||||
@media (max-width: 860px) {
|
@media (max-width: 860px) {
|
||||||
.success-layout {
|
.success-layout {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
expiresMeta: document.getElementById("expires-meta"),
|
expiresMeta: document.getElementById("expires-meta"),
|
||||||
captchaSlot: document.getElementById("captcha-slot"),
|
captchaSlot: document.getElementById("captcha-slot"),
|
||||||
sizeMeter: document.getElementById("size-meter"),
|
sizeMeter: document.getElementById("size-meter"),
|
||||||
|
checkPasswordItem: document.getElementById("check-password-item"),
|
||||||
shareNative: document.getElementById("share-native"),
|
shareNative: document.getElementById("share-native"),
|
||||||
downloadQr: document.getElementById("download-qr"),
|
downloadQr: document.getElementById("download-qr"),
|
||||||
};
|
};
|
||||||
@@ -333,9 +334,11 @@
|
|||||||
if (password) {
|
if (password) {
|
||||||
els.sharePassword.value = password;
|
els.sharePassword.value = password;
|
||||||
els.passwordBlock.classList.remove("hidden");
|
els.passwordBlock.classList.remove("hidden");
|
||||||
|
els.checkPasswordItem?.classList.remove("hidden");
|
||||||
} else {
|
} else {
|
||||||
els.sharePassword.value = "";
|
els.sharePassword.value = "";
|
||||||
els.passwordBlock.classList.add("hidden");
|
els.passwordBlock.classList.add("hidden");
|
||||||
|
els.checkPasswordItem?.classList.add("hidden");
|
||||||
}
|
}
|
||||||
renderShareQr(link);
|
renderShareQr(link);
|
||||||
syncShareControls();
|
syncShareControls();
|
||||||
|
|||||||
+16
-14
@@ -66,6 +66,15 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ul class="success-checklist" id="success-checklist">
|
||||||
|
<li data-i18n="create.checkLink">Copy the share link</li>
|
||||||
|
<li id="check-password-item" class="hidden" data-i18n="create.checkPassword">Send the password in a separate message</li>
|
||||||
|
<li data-i18n="create.checkExpires">Note the expiry time</li>
|
||||||
|
</ul>
|
||||||
|
<p class="hint success-trust" data-i18n="create.trustKey">
|
||||||
|
The encryption key lives only in the link #fragment — the server never sees it.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="success-layout">
|
<div class="success-layout">
|
||||||
<div class="success-main">
|
<div class="success-main">
|
||||||
<div id="success-password-block" class="success-password-block hidden">
|
<div id="success-password-block" class="success-password-block hidden">
|
||||||
@@ -94,28 +103,21 @@
|
|||||||
<input id="share-token" class="mono" readonly />
|
<input id="share-token" class="mono" readonly />
|
||||||
<button type="button" class="btn" id="copy-token" data-i18n="common.copy">Copy</button>
|
<button type="button" class="btn" id="copy-token" data-i18n="common.copy">Copy</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="success-actions">
|
||||||
|
<button type="button" class="btn hidden" id="share-native" data-i18n="create.share">Share</button>
|
||||||
|
<button type="button" class="btn" id="download-qr" data-i18n="create.downloadQr">Download QR</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="expires-meta" id="expires-meta"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="success-qr" aria-label="QR code">
|
<div class="success-qr" aria-label="QR code">
|
||||||
<div id="share-qr" class="share-qr"></div>
|
<div id="share-qr" class="share-qr"></div>
|
||||||
<p class="hint success-qr-hint" data-i18n="create.qrHint">Scan to open the share link</p>
|
<p class="hint success-qr-hint" data-i18n="create.qrHint">Scan to open the share link</p>
|
||||||
<div class="success-qr-actions">
|
|
||||||
<button type="button" class="qr-action-btn hidden" id="share-native" aria-describedby="share-native-tip">
|
|
||||||
<i class="fa-solid fa-share-nodes" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only" data-i18n="create.share">Share</span>
|
|
||||||
<span class="ui-tooltip" id="share-native-tip" role="tooltip" data-i18n="create.share">Share</span>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="qr-action-btn" id="download-qr" aria-describedby="download-qr-tip">
|
|
||||||
<i class="fa-solid fa-download" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only" data-i18n="create.downloadQr">Download QR</span>
|
|
||||||
<span class="ui-tooltip" id="download-qr-tip" role="tooltip" data-i18n="create.downloadQr">Download QR</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="expires-meta" id="expires-meta"></p>
|
|
||||||
|
|
||||||
<button type="button" class="btn ghost" id="create-another" data-i18n="create.another">Create another</button>
|
<button type="button" class="btn ghost" id="create-another" data-i18n="create.another">Create another</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ apiVersion: v2
|
|||||||
name: wrapped
|
name: wrapped
|
||||||
description: Zero-knowledge one-time encrypted drop (Wrapped)
|
description: Zero-knowledge one-time encrypted drop (Wrapped)
|
||||||
type: application
|
type: application
|
||||||
version: 0.1.3
|
version: 0.1.4
|
||||||
appVersion: "0.1.3"
|
appVersion: "0.1.4"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ replicaCount: 1
|
|||||||
|
|
||||||
image:
|
image:
|
||||||
repository: inecs/wrapped
|
repository: inecs/wrapped
|
||||||
tag: "0.1.3"
|
tag: "0.1.4"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
service:
|
service:
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "wrapped"
|
name = "wrapped"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
description = "Zero-knowledge one-time encrypted drop service"
|
description = "Zero-knowledge one-time encrypted drop service"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
Reference in New Issue
Block a user