commit d1589a3eece6ef8390843ebde2fb8c166c695169
parent 50f768fa601e4a891cecd122687553fe89a72606
Author: Sebastian <sebasjm@taler-systems.com>
Date: Sun, 14 Dec 2025 17:07:48 -0300
fix #10639
Diffstat:
4 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -414,7 +414,7 @@ const ALL_ELEMENTS = Object.values(UIElement).reduce((prev, ui) => {
return prev;
}, {} as ElementMap);
-function getAvailableForPersona(p: MerchantPersona): ElementMap {
+export function getAvailableForPersona(p: MerchantPersona): ElementMap {
switch (p) {
case "developer":
return ALL_ELEMENTS;
@@ -445,6 +445,7 @@ function getAvailableForPersona(p: MerchantPersona): ElementMap {
[UIElement.sidebar_subscriptions]: false,
[UIElement.sidebar_tokenFamilies]: false,
[UIElement.option_ageRestriction]: false,
+ [UIElement.option_refreshableScopes]: false,
};
case "offline-vending-machine":
return {
@@ -473,6 +474,7 @@ function getAvailableForPersona(p: MerchantPersona): ElementMap {
[UIElement.action_useRevenueApi]: false,
[UIElement.option_inventoryTaxes]: false,
[UIElement.sidebar_statistics]: false,
+ [UIElement.option_refreshableScopes]: false,
};
// case "inperson-vending-with-inventory":
case "point-of-sale":
@@ -502,6 +504,7 @@ function getAvailableForPersona(p: MerchantPersona): ElementMap {
[UIElement.action_useRevenueApi]: false,
[UIElement.option_inventoryTaxes]: false,
[UIElement.sidebar_statistics]: false,
+ [UIElement.option_refreshableScopes]: false,
};
case "digital-publishing":
return {
@@ -530,6 +533,7 @@ function getAvailableForPersona(p: MerchantPersona): ElementMap {
[UIElement.option_ageRestriction]: false,
[UIElement.action_useRevenueApi]: false,
[UIElement.option_inventoryTaxes]: false,
+ [UIElement.option_refreshableScopes]: false,
};
case "e-commerce":
return {
@@ -558,6 +562,7 @@ function getAvailableForPersona(p: MerchantPersona): ElementMap {
[UIElement.option_ageRestriction]: false,
[UIElement.action_useRevenueApi]: false,
[UIElement.option_inventoryTaxes]: false,
+ [UIElement.option_refreshableScopes]: false,
};
}
}
diff --git a/packages/merchant-backoffice-ui/src/hooks/preference.ts b/packages/merchant-backoffice-ui/src/hooks/preference.ts
@@ -51,6 +51,7 @@ export enum UIElement {
option_paymentTimeoutOnTemplate,
option_ageRestriction,
option_inventoryTaxes,
+ option_refreshableScopes,
}
export interface Preferences {
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accessTokens/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accessTokens/create/CreatePage.tsx
@@ -47,6 +47,8 @@ import { NotificationCard } from "../../../../components/menu/index.js";
import { SolveMFAChallenges } from "../../../../components/SolveMFA.js";
import { useSessionContext } from "../../../../context/session.js";
import { undefinedIfEmpty } from "../../../../utils/table.js";
+import { getAvailableForPersona } from "../../../../components/menu/SideBar.js";
+import { UIElement, usePreference } from "../../../../hooks/preference.js";
const TALER_SCREEN_ID = 29;
@@ -62,7 +64,7 @@ interface Props {
onBack?: () => void;
}
-const VALID_TOKEN_SCOPE = [
+const ALL_VALID_TOKEN_SCOPE = [
"",
LoginTokenScope.ReadOnly,
LoginTokenScope.OrderSimple,
@@ -77,6 +79,15 @@ const VALID_TOKEN_SCOPE = [
LoginTokenScope.OrderFull_Refreshable,
LoginTokenScope.All,
];
+const SANE_VALID_TOKEN_SCOPE = [
+ "",
+ LoginTokenScope.ReadOnly,
+ LoginTokenScope.OrderSimple,
+ LoginTokenScope.OrderPos,
+ LoginTokenScope.OrderManagement,
+ LoginTokenScope.OrderFull,
+ LoginTokenScope.All,
+];
export function CreatePage({ onCreated, onBack }: Props): VNode {
const { i18n } = useTranslationContext();
@@ -90,6 +101,12 @@ export function CreatePage({ onCreated, onBack }: Props): VNode {
description: !state.description ? i18n.str`Required` : undefined,
scope: !state.scope ? i18n.str`Required` : undefined,
});
+ const [{ persona }] = usePreference();
+ const scopeList = getAvailableForPersona(persona ?? "developer")[
+ UIElement.option_refreshableScopes
+ ]
+ ? ALL_VALID_TOKEN_SCOPE
+ : SANE_VALID_TOKEN_SCOPE;
const hasErrors = errors !== undefined;
@@ -179,7 +196,7 @@ export function CreatePage({ onCreated, onBack }: Props): VNode {
name="scope"
label={i18n.str`Scope`}
tooltip={i18n.str`The scope defines the set of permissions for the access token. Refreshable tokens has the permission to extend the expiration time.`}
- values={VALID_TOKEN_SCOPE}
+ values={scopeList}
help={((s) => {
if (!s) return "";
switch (s) {
diff --git a/packages/taler-util/src/time.ts b/packages/taler-util/src/time.ts
@@ -303,6 +303,16 @@ export namespace Duration {
return -1;
}
+ export function add(d1: Duration, d2: Duration): Duration {
+ if (d1.d_ms === "forever") {
+ return Duration.getForever();
+ }
+ if (d2.d_ms === "forever") {
+ return Duration.getForever();
+ }
+ return Duration.fromMilliseconds(d1.d_ms + d2.d_ms);
+ }
+
export function max(d1: Duration, d2: Duration): Duration {
return durationMax(d1, d2);
}