From c2214eaa10fe1a8779ea98d787d9ce9ab9869520 Mon Sep 17 00:00:00 2001 From: Mike Marseglia Date: Wed, 18 Jun 2025 22:43:12 -0400 Subject: [PATCH 1/4] Rename all references to config2.sh as config.sh for unified authentication script usage --- README.md | 16 +++++++----- api.scouting.org-command.sh | 7 ++++++ config.sh | 50 +++++++++++++++++++++++++++++++++---- docs/authentication.md | 26 +++++++++++++------ 4 files changed, 81 insertions(+), 18 deletions(-) mode change 100644 => 100755 config.sh diff --git a/README.md b/README.md index e581309..a36a200 100644 --- a/README.md +++ b/README.md @@ -34,15 +34,19 @@ npm install ## Setup Some API calls require authentication or parameters, such as a user's ID to get a person's Leadership History -`/advancements/youth/${userId}/leadershipPositionHistory`. These are configured as shell variables in the config file, +`/advancements/youth/${userId}/leadershipPositionHistory`. These are configured as shell variables using the authentication script, [config.sh](config.sh). -| Variable | Description | -|----------|-------------| -| userId | User ID of the person. Not the same as Member ID. | -| TOKEN | JWT token for authentication to protected endpoints. [docs/authentication.md](docs/authentication.md) | +To set up authentication: +1. Source the config.sh script with your my.scouting.org credentials: + ```shell + source config.sh + ``` +2. This will automatically set the required environment variables: + - `userId`: User ID of the person (automatically fetched) + - `TOKEN`: JWT token for authentication (automatically fetched) -Some tests will fail if you do not change the default values in the config file. +Some tests will fail if you do not set up authentication using the config.sh script. ## Usage diff --git a/api.scouting.org-command.sh b/api.scouting.org-command.sh index bd9ae3a..014d42d 100644 --- a/api.scouting.org-command.sh +++ b/api.scouting.org-command.sh @@ -1,5 +1,12 @@ #!/usr/bin/env bash +# Check if authentication is set up +if [ -z "$TOKEN" ] || [ -z "$userId" ]; then + echo "Error: Authentication not set up. Please run:" + echo "source config.sh " + exit 1 +fi + # shellcheck disable=SC1091 source config.sh diff --git a/config.sh b/config.sh old mode 100644 new mode 100755 index 3e22bb0..034bcbe --- a/config.sh +++ b/config.sh @@ -1,7 +1,47 @@ -#!/usr/bin/sh +#!/bin/bash -# User ID of the person. Not the same as Member ID. -userId="12345" +# This script must be sourced to set environment variables in the parent shell. +# Usage: source config.sh -# JWT token for authentication to protected endpoints. [docs/authentication.md](docs/authentication.md) -TOKEN="value" +# Check if both username and password are provided as command-line arguments +if [ "$#" -ne 2 ]; then + echo "Usage: source $0 " + return 1 # Use 'return' instead of 'exit' to avoid killing the parent shell +fi + +# Fetch the username and password from the command-line arguments +USERNAME=$1 +PASSWORD=$2 + +# Construct the login URL dynamically based on the username +LOGIN_URL="https://my.scouting.org/api/users/${USERNAME}/authenticate" + +# Send the login request using curl +RESPONSE=$(curl -s -X POST "$LOGIN_URL" \ + -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -H "Accept: application/json; version=2" \ + --data-urlencode "password=$PASSWORD") + +# Extract the Bearer token and userId from the JSON response using jq +BEARER_TOKEN=$(echo "$RESPONSE" | jq -r '.token') +USER_ID=$(echo "$RESPONSE" | jq -r '.account.userId') + +# Check if the token and userId were found +if [ "$BEARER_TOKEN" != "null" ] && [ "$USER_ID" != "null" ]; then + # Set the environment variables + export userId="$USER_ID" + export TOKEN="$BEARER_TOKEN" + + # Output the variables + echo "Bearer Token: $TOKEN" + echo "User ID: $USER_ID" + + # Unset intermediate variables for cleanliness + unset RESPONSE + unset BEARER_TOKEN + unset USER_ID +else + echo "Failed to retrieve Bearer token or User ID." + return 1 +fi diff --git a/docs/authentication.md b/docs/authentication.md index 2bf7d7f..2784dbc 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -1,16 +1,28 @@ - # Authentication and Authorization Describes authentication and authorization. ## Obtaining a JWT Token -- Log into Scoutbook or Internet Advancement -- Open your browser's Web Developer Console -- Look at the Network tab and find a HTTP request to api.scouting.org -- Look at the request headers and find the Authorization header -- Copy the token -- Update the variable `TOKEN` in the config file `config.sh`. +There are two ways to obtain a JWT token: + +### Automatic Method (Recommended) +Use the `config.sh` script which automatically fetches the token: +```shell +source config.sh +``` + +### Manual Method +If you need to manually obtain a token: +1. Log into Scoutbook or Internet Advancement +2. Open your browser's Web Developer Console +3. Look at the Network tab and find a HTTP request to api.scouting.org +4. Look at the request headers and find the Authorization header +5. Copy the token +6. Set it as an environment variable: + ```shell + export TOKEN="your-token-here" + ``` ## JWT Token Schema From d1f5e99ab4bcbb9de7c025bccd54dbdd0fcaa06e Mon Sep 17 00:00:00 2001 From: Mike Marseglia Date: Thu, 19 Jun 2025 06:39:24 -0400 Subject: [PATCH 2/4] ignore adsf config file --- .gitignore | 4 +++- config2.sh | 47 -------------------------------------- generate_markdown.sh | 2 ++ package-lock.json | 54 +++++++++++++++++++++++++++++++++++++++++++- package.json | 5 +++- 5 files changed, 62 insertions(+), 50 deletions(-) delete mode 100644 config2.sh diff --git a/.gitignore b/.gitignore index 3abc7a1..2b991bb 100644 --- a/.gitignore +++ b/.gitignore @@ -85,4 +85,6 @@ dist/ .fusebox/ # DynamoDB Local files -.dynamodb/ \ No newline at end of file +.dynamodb/ +.aider* +.tool-versions \ No newline at end of file diff --git a/config2.sh b/config2.sh deleted file mode 100644 index d1bf918..0000000 --- a/config2.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -# This script must be sourced to set environment variables in the parent shell. -# Usage: source config2.sh - -# Check if both username and password are provided as command-line arguments -if [ "$#" -ne 2 ]; then - echo "Usage: source $0 " - return 1 # Use 'return' instead of 'exit' to avoid killing the parent shell -fi - -# Fetch the username and password from the command-line arguments -USERNAME=$1 -PASSWORD=$2 - -# Construct the login URL dynamically based on the username -LOGIN_URL="https://my.scouting.org/api/users/${USERNAME}/authenticate" - -# Send the login request using curl -RESPONSE=$(curl -s -X POST "$LOGIN_URL" \ - -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" \ - -H "Content-Type: application/x-www-form-urlencoded" \ - -H "Accept: application/json; version=2" \ - --data-urlencode "password=$PASSWORD") - -# Extract the Bearer token and userId from the JSON response using jq -BEARER_TOKEN=$(echo "$RESPONSE" | jq -r '.token') -USER_ID=$(echo "$RESPONSE" | jq -r '.account.userId') - -# Check if the token and userId were found -if [ "$BEARER_TOKEN" != "null" ] && [ "$USER_ID" != "null" ]; then - # Set the environment variables - export userId="$USER_ID" - export TOKEN="$BEARER_TOKEN" - - # Output the variables - echo "Bearer Token: $TOKEN" - echo "User ID: $USER_ID" - - # Unset intermediate variables for cleanliness - unset RESPONSE - unset BEARER_TOKEN - unset USER_ID -else - echo "Failed to retrieve Bearer token or User ID." - return 1 -fi diff --git a/generate_markdown.sh b/generate_markdown.sh index b19fcfc..bafead7 100755 --- a/generate_markdown.sh +++ b/generate_markdown.sh @@ -2,6 +2,8 @@ echo "| Variable | Description |" echo "|----------|-------------|" +echo "| userId | User ID of the person (automatically fetched from my.scouting.org) |" +echo "| TOKEN | JWT token for authentication (automatically fetched from my.scouting.org) |" # Read the config file line by line while IFS= read -r line; do diff --git a/package-lock.json b/package-lock.json index 2b936f8..32f694c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,69 @@ { "name": "scouting-api", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "scouting-api", + "version": "1.0.0", "dependencies": { - "optic": "^0.1.0" + "csv-writer": "^1.6.0", + "fs": "^0.0.1-security", + "optic": "^0.1.0", + "path": "^0.12.7" } }, + "node_modules/csv-writer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz", + "integrity": "sha512-NOx7YDFWEsM/fTRAJjRpPp8t+MKRVvniAg9wQlUKx20MFrPs73WLJhFf5iteqrxNYnsy924K3Iroh3yNHeYd2g==", + "license": "MIT" + }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==", + "license": "ISC" + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "license": "ISC" + }, "node_modules/optic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/optic/-/optic-0.1.0.tgz", "integrity": "sha512-wKwjUiGzELOVU62sqmbBDWBDS9iGhsVwdO24cRY3VlHDjhHwnDXa9s+er311Jbrm2jYwD3aGitv7wvBzXH+bOA==" + }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "license": "MIT", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } } } } diff --git a/package.json b/package.json index 9b061ac..36e55ee 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,9 @@ "openapi-update": "optic capture api.scouting.org/openapi.yaml --update interactive" }, "dependencies": { - "optic": "^0.1.0" + "csv-writer": "^1.6.0", + "fs": "^0.0.1-security", + "optic": "^0.1.0", + "path": "^0.12.7" } } From 01d36b6a7b0179cb92988df2235adbb115d6188e Mon Sep 17 00:00:00 2001 From: Mike Marseglia Date: Tue, 1 Jul 2025 08:51:52 -0400 Subject: [PATCH 3/4] Use env vars directly in config.sh --- README.md | 6 ++++-- api.scouting.org-command.sh | 4 +++- config.sh | 41 +++++++++++++++++++++++++------------ docs/authentication.md | 4 +++- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a36a200..6a5a073 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,11 @@ Some API calls require authentication or parameters, such as a user's ID to get [config.sh](config.sh). To set up authentication: -1. Source the config.sh script with your my.scouting.org credentials: +1. Export your my.scouting.org credentials as environment variables and then source the script: ```shell - source config.sh + export SCOUT_USERNAME= + export SCOUT_PASSWORD= + source config.sh ``` 2. This will automatically set the required environment variables: - `userId`: User ID of the person (automatically fetched) diff --git a/api.scouting.org-command.sh b/api.scouting.org-command.sh index 014d42d..c7d9cc4 100644 --- a/api.scouting.org-command.sh +++ b/api.scouting.org-command.sh @@ -3,7 +3,9 @@ # Check if authentication is set up if [ -z "$TOKEN" ] || [ -z "$userId" ]; then echo "Error: Authentication not set up. Please run:" - echo "source config.sh " + echo "export SCOUT_USERNAME=" + echo "export SCOUT_PASSWORD=" + echo "source config.sh" exit 1 fi diff --git a/config.sh b/config.sh index 034bcbe..340b6e3 100755 --- a/config.sh +++ b/config.sh @@ -1,27 +1,40 @@ #!/bin/bash +# Save and set safe shell options +SAVED_OPTIONS="$(set +o)" +set -euo pipefail +trap 'eval "$SAVED_OPTIONS"' RETURN + # This script must be sourced to set environment variables in the parent shell. -# Usage: source config.sh +# Usage: +# export SCOUT_USERNAME= +# export SCOUT_PASSWORD= +# source config.sh -# Check if both username and password are provided as command-line arguments -if [ "$#" -ne 2 ]; then - echo "Usage: source $0 " +# Ensure the username and password are provided via environment variables +if [ -z "${SCOUT_USERNAME:-}" ] || [ -z "${SCOUT_PASSWORD:-}" ]; then + echo "Error: SCOUT_USERNAME and SCOUT_PASSWORD must be set before sourcing this script." return 1 # Use 'return' instead of 'exit' to avoid killing the parent shell fi -# Fetch the username and password from the command-line arguments -USERNAME=$1 -PASSWORD=$2 +# Verify dependencies +for cmd in curl jq; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "Error: $cmd is required but not installed." >&2 + return 1 + fi +done + # Construct the login URL dynamically based on the username -LOGIN_URL="https://my.scouting.org/api/users/${USERNAME}/authenticate" +LOGIN_URL="https://my.scouting.org/api/users/${SCOUT_USERNAME}/authenticate" # Send the login request using curl -RESPONSE=$(curl -s -X POST "$LOGIN_URL" \ +RESPONSE=$(curl -s --fail -X POST "$LOGIN_URL" \ -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" \ -H "Content-Type: application/x-www-form-urlencoded" \ -H "Accept: application/json; version=2" \ - --data-urlencode "password=$PASSWORD") + --data-urlencode "password=$SCOUT_PASSWORD") # Extract the Bearer token and userId from the JSON response using jq BEARER_TOKEN=$(echo "$RESPONSE" | jq -r '.token') @@ -33,14 +46,16 @@ if [ "$BEARER_TOKEN" != "null" ] && [ "$USER_ID" != "null" ]; then export userId="$USER_ID" export TOKEN="$BEARER_TOKEN" - # Output the variables - echo "Bearer Token: $TOKEN" - echo "User ID: $USER_ID" + # Optionally output the variables for debugging + # echo "Bearer Token: $TOKEN" + # echo "User ID: $USER_ID" # Unset intermediate variables for cleanliness unset RESPONSE unset BEARER_TOKEN unset USER_ID + unset SCOUT_USERNAME + unset SCOUT_PASSWORD else echo "Failed to retrieve Bearer token or User ID." return 1 diff --git a/docs/authentication.md b/docs/authentication.md index 2784dbc..ccf2bd5 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -9,7 +9,9 @@ There are two ways to obtain a JWT token: ### Automatic Method (Recommended) Use the `config.sh` script which automatically fetches the token: ```shell -source config.sh +export SCOUT_USERNAME= +export SCOUT_PASSWORD= +source config.sh ``` ### Manual Method From 53d7bf789f88f8867091e409ea5b6f2b43130ab7 Mon Sep 17 00:00:00 2001 From: Mike Marseglia Date: Tue, 1 Jul 2025 09:07:41 -0400 Subject: [PATCH 4/4] minor updates --- config.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.sh b/config.sh index 340b6e3..a7ccc47 100755 --- a/config.sh +++ b/config.sh @@ -1,8 +1,8 @@ -#!/bin/bash +#!/usr/bin/env bash # Save and set safe shell options SAVED_OPTIONS="$(set +o)" -set -euo pipefail +set -uo pipefail trap 'eval "$SAVED_OPTIONS"' RETURN # This script must be sourced to set environment variables in the parent shell. @@ -24,7 +24,7 @@ for cmd in curl jq; do return 1 fi done - +unset cmd # Unset the loop variable for cleanliness # Construct the login URL dynamically based on the username LOGIN_URL="https://my.scouting.org/api/users/${SCOUT_USERNAME}/authenticate"