v0.1.23 - Make role-as-password the default authorization model; remove interactive approval prompts from wizard; add Makefile guard to direct agents to build_static.sh; optimize build_static.sh with content-hash skip and fix .dockerignore to exclude 1.3GB of unnecessary files from Docker context
This commit is contained in:
@@ -4,3 +4,26 @@ build/
|
|||||||
/*.a
|
/*.a
|
||||||
!resources/
|
!resources/
|
||||||
!resources/**
|
!resources/**
|
||||||
|
|
||||||
|
# Exclude nested .git and bare repos inside resources/nostr_core_lib.
|
||||||
|
# These are not needed for the build and add ~1.3 GB to the Docker context.
|
||||||
|
resources/nostr_core_lib/.git/
|
||||||
|
resources/nostr_core_lib/rewrite_mirror/
|
||||||
|
resources/nostr_core_lib/verify_remote_size/
|
||||||
|
resources/nostr_core_lib/verify_remote_size_now/
|
||||||
|
resources/nostr_core_lib/backups/
|
||||||
|
resources/nostr_core_lib/examples/
|
||||||
|
resources/nostr_core_lib/tests/
|
||||||
|
resources/nostr_core_lib/plans/
|
||||||
|
resources/nostr_core_lib/pool.log
|
||||||
|
resources/nostr_core_lib/Trash/
|
||||||
|
resources/nostr_core_lib/node_modules/
|
||||||
|
resources/nostr_core_lib/nips/
|
||||||
|
resources/nostr_core_lib/nak/
|
||||||
|
resources/nostr_core_lib/nostr-tools/
|
||||||
|
resources/nostr_core_lib/libsodium/
|
||||||
|
resources/nostr_core_lib/monocypher-4.0.2/
|
||||||
|
resources/nostr_core_lib/tiny-AES-c/
|
||||||
|
resources/nostr_core_lib/blossom/
|
||||||
|
resources/nostr_core_lib/ndk/
|
||||||
|
resources/nostr_core_lib/cline_history/
|
||||||
|
|||||||
@@ -93,12 +93,38 @@ N_SIGNER_CLIENT_TARGET := $(BUILD_DIR)/nsigner_client
|
|||||||
|
|
||||||
.PHONY: all lib dev static static-debug static-arm64 firmware-feather test test-integration test-mnemonic test-mnemonic-input test-role test-selector test-enforcement test-dispatcher test-policy test-socket-name test-auth-envelope test-qrexec-auth test-mine-event test-pq-crypto test-ed25519-x25519 test-ml-dsa-65 test-slh-dsa-128s test-ml-kem-768 test-pubkey-format test-algorithm-api test-path-whitelist test-n-signer-client examples clients test-client clean
|
.PHONY: all lib dev static static-debug static-arm64 firmware-feather test test-integration test-mnemonic test-mnemonic-input test-role test-selector test-enforcement test-dispatcher test-policy test-socket-name test-auth-envelope test-qrexec-auth test-mine-event test-pq-crypto test-ed25519-x25519 test-ml-dsa-65 test-slh-dsa-128s test-ml-kem-768 test-pubkey-format test-algorithm-api test-path-whitelist test-n-signer-client examples clients test-client clean
|
||||||
|
|
||||||
|
# Guard for non-static build targets.
|
||||||
|
# The canonical build is `make static` (runs build_static.sh).
|
||||||
|
# To use dev/test targets, set NSIGNER_ALLOW_DEV_BUILD=1 in your environment.
|
||||||
|
# This prevents AI agents from accidentally using the wrong build path.
|
||||||
|
define BUILD_GUARD
|
||||||
|
@if [ -z "$$NSIGNER_ALLOW_DEV_BUILD" ]; then \
|
||||||
|
echo "=========================================================="; \
|
||||||
|
echo "ERROR: This target is blocked for non-interactive agents."; \
|
||||||
|
echo " For testing and deployment, use:"; \
|
||||||
|
echo ""; \
|
||||||
|
echo " ./build_static.sh"; \
|
||||||
|
echo " or"; \
|
||||||
|
echo " make static"; \
|
||||||
|
echo ""; \
|
||||||
|
echo " The static build produces the canonical binary that"; \
|
||||||
|
echo " matches production deployments."; \
|
||||||
|
echo ""; \
|
||||||
|
echo " To override (human developers only):"; \
|
||||||
|
echo " NSIGNER_ALLOW_DEV_BUILD=1 make <target>"; \
|
||||||
|
echo "=========================================================="; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
endef
|
||||||
|
|
||||||
all: dev clients
|
all: dev clients
|
||||||
|
|
||||||
lib:
|
lib:
|
||||||
|
$(BUILD_GUARD)
|
||||||
cd resources/nostr_core_lib && ./build.sh --nips=1,4,6,13,19,44
|
cd resources/nostr_core_lib && ./build.sh --nips=1,4,6,13,19,44
|
||||||
|
|
||||||
dev: lib $(TARGET_DEV)
|
dev: lib $(TARGET_DEV)
|
||||||
|
$(BUILD_GUARD)
|
||||||
|
|
||||||
$(TARGET_DEV): $(SOURCES)
|
$(TARGET_DEV): $(SOURCES)
|
||||||
@mkdir -p $(BUILD_DIR)
|
@mkdir -p $(BUILD_DIR)
|
||||||
|
|||||||
+75
-7
@@ -1,21 +1,26 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Build fully static MUSL binary for nsigner using Alpine Docker
|
# Build fully static MUSL binary for nsigner using Alpine Docker
|
||||||
|
#
|
||||||
|
# Speed optimization: if nothing changed since the last successful build,
|
||||||
|
# skip the Docker build entirely and reuse the existing binaries.
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
BUILD_DIR="$SCRIPT_DIR/build"
|
BUILD_DIR="$SCRIPT_DIR/build"
|
||||||
DOCKERFILE="$SCRIPT_DIR/Dockerfile.alpine-musl"
|
DOCKERFILE="$SCRIPT_DIR/Dockerfile.alpine-musl"
|
||||||
|
HASH_FILE="$BUILD_DIR/.nsigner_build_hash"
|
||||||
|
|
||||||
TARGET_ARCH=""
|
TARGET_ARCH=""
|
||||||
|
FORCE=0
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--arch)
|
--arch)
|
||||||
if [[ -z "${2:-}" ]]; then
|
if [[ -z "${2:-}" ]]; then
|
||||||
echo "ERROR: --arch requires a value"
|
echo "ERROR: --arch requires a value"
|
||||||
echo "Usage: $0 [--arch <x86_64|arm64|armv7>]"
|
echo "Usage: $0 [--arch <x86_64|arm64|armv7>] [--force]"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
case "$2" in
|
case "$2" in
|
||||||
@@ -30,9 +35,13 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--force)
|
||||||
|
FORCE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "ERROR: Unknown argument '$1'"
|
echo "ERROR: Unknown argument '$1'"
|
||||||
echo "Usage: $0 [--arch <x86_64|arm64|armv7>]"
|
echo "Usage: $0 [--arch <x86_64|arm64|armv7>] [--force]"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -78,7 +87,7 @@ case "$ARCH" in
|
|||||||
CLIENT_NAME="nsigner_client_static_arm64"
|
CLIENT_NAME="nsigner_client_static_arm64"
|
||||||
;;
|
;;
|
||||||
armv7)
|
armv7)
|
||||||
PLATFORM="linux/arm/v7"
|
PLATFORM="linux/v7"
|
||||||
OUTPUT_NAME="nsigner_static_armv7"
|
OUTPUT_NAME="nsigner_static_armv7"
|
||||||
CLIENT_NAME="nsigner_client_static_armv7"
|
CLIENT_NAME="nsigner_client_static_armv7"
|
||||||
;;
|
;;
|
||||||
@@ -109,6 +118,62 @@ echo "Output: $BUILD_DIR/$OUTPUT_NAME"
|
|||||||
echo "Client: $BUILD_DIR/$CLIENT_NAME"
|
echo "Client: $BUILD_DIR/$CLIENT_NAME"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# ---- Change detection ----
|
||||||
|
# Compute a hash of all files that feed into the Docker build.
|
||||||
|
# If the hash matches the last successful build and the output binaries
|
||||||
|
# exist, skip the Docker build entirely.
|
||||||
|
compute_source_hash() {
|
||||||
|
{
|
||||||
|
# Dockerfile itself
|
||||||
|
cat "$DOCKERFILE"
|
||||||
|
# .dockerignore
|
||||||
|
cat "$SCRIPT_DIR/.dockerignore" 2>/dev/null || true
|
||||||
|
# All source files
|
||||||
|
find "$SCRIPT_DIR/src" "$SCRIPT_DIR/client" "$SCRIPT_DIR/libotppad" \
|
||||||
|
"$SCRIPT_DIR/resources/tui_continuous" "$SCRIPT_DIR/resources/pqclean" \
|
||||||
|
-type f -not -path '*/.git/*' 2>/dev/null | sort | xargs cat 2>/dev/null
|
||||||
|
# nostr_core_lib source (exclude .git, backups, bare repos, examples, tests)
|
||||||
|
find "$SCRIPT_DIR/resources/nostr_core_lib" \
|
||||||
|
-type f \
|
||||||
|
-not -path '*/.git/*' \
|
||||||
|
-not -path '*/rewrite_mirror/*' \
|
||||||
|
-not -path '*/verify_remote_size*' \
|
||||||
|
-not -path '*/backups/*' \
|
||||||
|
-not -path '*/examples/*' \
|
||||||
|
-not -path '*/tests/*' \
|
||||||
|
-not -path '*/Trash/*' \
|
||||||
|
-not -path '*/node_modules/*' \
|
||||||
|
-not -path '*/nips/*' \
|
||||||
|
-not -path '*/nak/*' \
|
||||||
|
-not -path '*/nostr-tools/*' \
|
||||||
|
-not -path '*/libsodium/*' \
|
||||||
|
-not -path '*/monocypher*' \
|
||||||
|
-not -path '*/tiny-AES-c/*' \
|
||||||
|
-not -path '*/blossom/*' \
|
||||||
|
-not -path '*/ndk/*' \
|
||||||
|
-not -path '*/cline_history/*' \
|
||||||
|
2>/dev/null | sort | xargs cat 2>/dev/null
|
||||||
|
} | sha256sum | awk '{print $1}'
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_HASH="$(compute_source_hash)"
|
||||||
|
OUTPUT_PATH="$BUILD_DIR/$OUTPUT_NAME"
|
||||||
|
CLIENT_PATH="$BUILD_DIR/$CLIENT_NAME"
|
||||||
|
|
||||||
|
if [[ "$FORCE" -eq 0 ]] && \
|
||||||
|
[[ -f "$OUTPUT_PATH" ]] && \
|
||||||
|
[[ -f "$CLIENT_PATH" ]] && \
|
||||||
|
[[ -f "$HASH_FILE" ]] && \
|
||||||
|
[[ "$(cat "$HASH_FILE" 2>/dev/null)" == "$CURRENT_HASH" ]]; then
|
||||||
|
echo "No changes detected since last successful build."
|
||||||
|
echo "Skipping Docker build. Existing binaries:"
|
||||||
|
echo " $OUTPUT_PATH"
|
||||||
|
echo " $CLIENT_PATH"
|
||||||
|
echo ""
|
||||||
|
echo "Use --force to rebuild anyway."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$ARCH" != "$HOST_ARCH" ]; then
|
if [ "$ARCH" != "$HOST_ARCH" ]; then
|
||||||
echo "[0/3] Preparing buildx + QEMU for cross-architecture build"
|
echo "[0/3] Preparing buildx + QEMU for cross-architecture build"
|
||||||
if ! docker buildx inspect >/dev/null 2>&1; then
|
if ! docker buildx inspect >/dev/null 2>&1; then
|
||||||
@@ -126,10 +191,10 @@ if [ "$ARCH" != "$HOST_ARCH" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[1/3] Building builder stage from project root context"
|
echo "[1/3] Building builder stage from project root context"
|
||||||
# Remove previous builder image to avoid dangling <none> images piling up
|
# Note: we no longer docker rmi before building. The buildx cache handles
|
||||||
# across repeated builds (each rebuild untagges the old image, leaving ~422MB
|
# layer reuse, and the prune at the end prevents dangling images. Removing
|
||||||
# of garbage per build otherwise).
|
# the image here forced a full --load re-export (~370MB) every time even
|
||||||
docker rmi "$IMAGE_TAG" >/dev/null 2>&1 || true
|
# when all layers were cache hits.
|
||||||
docker buildx build \
|
docker buildx build \
|
||||||
--platform "$PLATFORM" \
|
--platform "$PLATFORM" \
|
||||||
--target builder \
|
--target builder \
|
||||||
@@ -173,6 +238,9 @@ echo "Build complete:"
|
|||||||
echo " $BUILD_DIR/$OUTPUT_NAME"
|
echo " $BUILD_DIR/$OUTPUT_NAME"
|
||||||
echo " $BUILD_DIR/$CLIENT_NAME"
|
echo " $BUILD_DIR/$CLIENT_NAME"
|
||||||
|
|
||||||
|
# Record the source hash so the next run can skip if nothing changed.
|
||||||
|
echo "$CURRENT_HASH" > "$HASH_FILE"
|
||||||
|
|
||||||
# Prune stale build cache older than 24h to prevent unbounded cache growth
|
# Prune stale build cache older than 24h to prevent unbounded cache growth
|
||||||
# from repeated buildx builds. Recent layers are kept for fast rebuilds.
|
# from repeated buildx builds. Recent layers are kept for fast rebuilds.
|
||||||
docker builder prune -af --filter "until=24h" >/dev/null 2>&1 || true
|
docker builder prune -af --filter "until=24h" >/dev/null 2>&1 || true
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
# Plan: Role-as-Password as the Default Authorization Model
|
||||||
|
|
||||||
|
## Status: Draft — ready for review
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
The signer currently defaults to requiring interactive approval for every request, even for the default "main" role. This contradicts the intended design where **knowing the role name is sufficient authorization** (role-as-password). Users running v0.1.21 are prompted to approve requests when they should be authorized automatically.
|
||||||
|
|
||||||
|
## Root cause
|
||||||
|
|
||||||
|
Three places in the code set `requires_approval = 1` by default:
|
||||||
|
|
||||||
|
| Location | Context | Current value |
|
||||||
|
|---|---|---|
|
||||||
|
| [`src/main.c:3816`](../src/main.c:3816) | Default "main" role (non-interactive mode) | `requires_approval = 1` |
|
||||||
|
| [`src/main.c:2374`](../src/main.c:2374) | Wizard role creation prompt | Default `1` (Y/n) |
|
||||||
|
| [`src/main.c:2223`](../src/main.c:2223) | Wizard OTP role creation prompt | Default `1` (Y/n) |
|
||||||
|
|
||||||
|
## Changes required
|
||||||
|
|
||||||
|
### 1. Default "main" role — non-interactive mode
|
||||||
|
|
||||||
|
**File:** [`src/main.c:3816`](../src/main.c:3816)
|
||||||
|
|
||||||
|
Change:
|
||||||
|
```c
|
||||||
|
role.requires_approval = 1;
|
||||||
|
```
|
||||||
|
To:
|
||||||
|
```c
|
||||||
|
role.requires_approval = 0; /* role-as-password: knowing the role name is sufficient */
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the most critical fix — it affects every user running in non-interactive mode (e.g., `--listen unix`, `--listen tcp`, `--listen qrexec`).
|
||||||
|
|
||||||
|
### 2. Wizard role creation — remove approval prompt
|
||||||
|
|
||||||
|
**File:** [`src/main.c:2359-2377`](../src/main.c:2359)
|
||||||
|
|
||||||
|
Currently the wizard asks:
|
||||||
|
```
|
||||||
|
Require interactive approval for each request? [Y/n]:
|
||||||
|
```
|
||||||
|
|
||||||
|
With role-as-password as the default, this prompt should be **removed entirely**. The role is created with `requires_approval = 0`. If a user wants approval, they can use `--preapprove` or manually edit the role after creation.
|
||||||
|
|
||||||
|
Remove the prompt block (lines 2359-2377) and set:
|
||||||
|
```c
|
||||||
|
int requires_approval = 0; /* role-as-password by default */
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Wizard OTP role creation — remove approval prompt
|
||||||
|
|
||||||
|
**File:** [`src/main.c:2208-2226`](../src/main.c:2208)
|
||||||
|
|
||||||
|
Same change as #2. Remove the approval prompt for OTP roles and default to `requires_approval = 0`.
|
||||||
|
|
||||||
|
### 4. Policy table default — no change needed
|
||||||
|
|
||||||
|
**File:** [`src/policy.c:1097-1113`](../src/policy.c:1097)
|
||||||
|
|
||||||
|
The current default policy is `* → PROMPT_EVERY_REQUEST`. This is correct because:
|
||||||
|
|
||||||
|
- For roles with `requires_approval = 0`, [`policy_check_with_role()`](../src/policy.c:1305) returns `POLICY_ALLOW` **before** consulting the policy table.
|
||||||
|
- For roles with `requires_approval = 1`, the policy table prompt still fires as expected.
|
||||||
|
|
||||||
|
No change needed here.
|
||||||
|
|
||||||
|
### 5. `--allow-all` flag — retain as-is
|
||||||
|
|
||||||
|
**File:** [`src/main.c:3678`](../src/main.c:3678)
|
||||||
|
|
||||||
|
The `--allow-all` flag sets `g_prompt_always_allow`, which bypasses prompts for algorithm-based verbs (sign, verify, encapsulate, etc.) that don't go through the role system. This is still useful for testing and non-interactive scenarios. No change needed.
|
||||||
|
|
||||||
|
## Authorization flow after changes
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A[Client sends request with role name] --> B{Role found?}
|
||||||
|
B -- No --> C[Reject: unknown_role]
|
||||||
|
B -- Yes --> D{requires_approval?}
|
||||||
|
D -- No --> E[Authorize immediately - role-as-password]
|
||||||
|
D -- Yes --> F[Check policy table]
|
||||||
|
F --> G{Policy match?}
|
||||||
|
G -- Allow --> H[Authorize]
|
||||||
|
G -- Prompt --> I[Show interactive prompt]
|
||||||
|
G -- Deny --> J[Reject: policy_denied]
|
||||||
|
I --> K{User choice}
|
||||||
|
K -- y --> H
|
||||||
|
K -- a/e --> L[Add session grant] --> H
|
||||||
|
K -- n --> J
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test impact
|
||||||
|
|
||||||
|
- [`tests/test_n_signer_client.sh`](../tests/test_n_signer_client.sh) — may need updates if tests relied on the old approval-required default
|
||||||
|
- [`tests/test_integration.c`](../tests/test_integration.c) — verify no tests break from the default change
|
||||||
|
- The `NSIGNER_TEST_FORCE_PROMPT` env var ([`src/main.c:3063`](../src/main.c:3063)) can be used to force prompts in tests that need to exercise the approval path
|
||||||
|
|
||||||
|
## Files to modify
|
||||||
|
|
||||||
|
| File | Lines | Change |
|
||||||
|
|---|---|---|
|
||||||
|
| [`src/main.c`](../src/main.c) | 3816 | `requires_approval = 1` → `0` |
|
||||||
|
| [`src/main.c`](../src/main.c) | 2359-2377 | Remove approval prompt, default to `0` |
|
||||||
|
| [`src/main.c`](../src/main.c) | 2208-2226 | Remove approval prompt, default to `0` |
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Three one-line changes (plus removing two prompt blocks) to make role-as-password the default. The mechanism already exists in the code — it's just not the default.
|
||||||
+9
-39
@@ -813,8 +813,8 @@ int socket_name_random(char *out, size_t out_len);
|
|||||||
/* Version information (auto-updated by build/version tooling) */
|
/* Version information (auto-updated by build/version tooling) */
|
||||||
#define NSIGNER_VERSION_MAJOR 0
|
#define NSIGNER_VERSION_MAJOR 0
|
||||||
#define NSIGNER_VERSION_MINOR 1
|
#define NSIGNER_VERSION_MINOR 1
|
||||||
#define NSIGNER_VERSION_PATCH 22
|
#define NSIGNER_VERSION_PATCH 23
|
||||||
#define NSIGNER_VERSION "v0.1.22"
|
#define NSIGNER_VERSION "v0.1.23"
|
||||||
|
|
||||||
|
|
||||||
/* NSIGNER_HEADERLESS_DECLS_END */
|
/* NSIGNER_HEADERLESS_DECLS_END */
|
||||||
@@ -2206,24 +2206,9 @@ static int prompt_named_path_roles(role_table_t *role_table) {
|
|||||||
strncpy(g_wizard_otp_spec, pad_spec, sizeof(g_wizard_otp_spec) - 1);
|
strncpy(g_wizard_otp_spec, pad_spec, sizeof(g_wizard_otp_spec) - 1);
|
||||||
g_wizard_otp_spec[sizeof(g_wizard_otp_spec) - 1] = '\0';
|
g_wizard_otp_spec[sizeof(g_wizard_otp_spec) - 1] = '\0';
|
||||||
|
|
||||||
/* requires_approval flag — OTP roles can still require approval. */
|
/* Role-as-password by default: knowing the role name is sufficient
|
||||||
printf(" Require interactive approval for each request? [Y/n]: ");
|
* authorization. No interactive approval prompt. */
|
||||||
fflush(stdout);
|
int requires_approval = 0;
|
||||||
char approval_choice[16];
|
|
||||||
if (read_line_stdin(approval_choice, sizeof(approval_choice)) != 0) {
|
|
||||||
return (roles_created > 0) ? 0 : -1;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t len = strlen(approval_choice);
|
|
||||||
while (len > 0 && (approval_choice[len-1] == '\n' || approval_choice[len-1] == '\r' ||
|
|
||||||
approval_choice[len-1] == ' ' || approval_choice[len-1] == '\t')) {
|
|
||||||
approval_choice[--len] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int requires_approval = 1;
|
|
||||||
if (approval_choice[0] == 'n' || approval_choice[0] == 'N') {
|
|
||||||
requires_approval = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register the OTP role. No curve/path derivation; the pad is the key. */
|
/* Register the OTP role. No curve/path derivation; the pad is the key. */
|
||||||
role_entry_t new_role;
|
role_entry_t new_role;
|
||||||
@@ -2357,24 +2342,9 @@ static int prompt_named_path_roles(role_table_t *role_table) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* requires_approval flag */
|
/* Role-as-password by default: knowing the role name is sufficient
|
||||||
printf(" Require interactive approval for each request? [Y/n]: ");
|
* authorization. No interactive approval prompt. */
|
||||||
fflush(stdout);
|
int requires_approval = 0;
|
||||||
char approval_choice[16];
|
|
||||||
if (read_line_stdin(approval_choice, sizeof(approval_choice)) != 0) {
|
|
||||||
return (roles_created > 0) ? 0 : -1;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t len = strlen(approval_choice);
|
|
||||||
while (len > 0 && (approval_choice[len-1] == '\n' || approval_choice[len-1] == '\r' ||
|
|
||||||
approval_choice[len-1] == ' ' || approval_choice[len-1] == '\t')) {
|
|
||||||
approval_choice[--len] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int requires_approval = 1; /* default: require approval */
|
|
||||||
if (approval_choice[0] == 'n' || approval_choice[0] == 'N') {
|
|
||||||
requires_approval = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No default index — the client always sends the full path, so keys
|
/* No default index — the client always sends the full path, so keys
|
||||||
* are derived on-demand when a request comes in. */
|
* are derived on-demand when a request comes in. */
|
||||||
@@ -3813,7 +3783,7 @@ int main(int argc, char *argv[]) {
|
|||||||
role.path_range_lo = -1;
|
role.path_range_lo = -1;
|
||||||
role.path_range_hi = -1;
|
role.path_range_hi = -1;
|
||||||
role.path_default_index = -1;
|
role.path_default_index = -1;
|
||||||
role.requires_approval = 1;
|
role.requires_approval = 0; /* role-as-password: knowing the role name is sufficient */
|
||||||
role.derived = 0;
|
role.derived = 0;
|
||||||
if (role_table_add(&role_table, &role) != 0) {
|
if (role_table_add(&role_table, &role) != 0) {
|
||||||
fprintf(stderr, "Failed to initialize default role\n");
|
fprintf(stderr, "Failed to initialize default role\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user