From 09b3b3543b83da596b1c89322858b0a751cfc496 Mon Sep 17 00:00:00 2001 From: Tommy Chow Date: Sun, 1 Mar 2026 20:09:39 -0800 Subject: [PATCH] add .env-based config, token script, and VS Code launch configs Move Twitch credentials from hardcoded launch.json args to a gitignored .env file read via --dart-define-from-file. Add a shell script to get a user auth token through the Authorization Code flow for easy emulator login. Update README with the new setup steps. Co-Authored-By: Claude Opus 4.6 --- .env.example | 2 + .gitignore | 5 +- .vscode/launch.json | 25 ++++++++++ README.md | 10 +++- scripts/get-twitch-token.sh | 91 +++++++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 .env.example create mode 100644 .vscode/launch.json create mode 100755 scripts/get-twitch-token.sh diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..4d4439a4 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +CLIENT_ID= +SECRET= diff --git a/.gitignore b/.gitignore index bb531e6b..1cbf0d64 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ migrate_working_dir/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. -.vscode/ +# .vscode/ # Flutter/Dart/Pub related **/doc/api/ @@ -64,5 +64,8 @@ random/ # potentially sensitive review information **/fastlane/metadata/review_information +# secrets +.env + # ai .claude/settings.local.json \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..dad4cfce --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "frosty", + "request": "launch", + "type": "dart", + "args": ["--dart-define-from-file=.env"] + }, + { + "name": "frosty (profile mode)", + "request": "launch", + "type": "dart", + "flutterMode": "profile", + "args": ["--dart-define-from-file=.env"] + }, + { + "name": "frosty (release mode)", + "request": "launch", + "type": "dart", + "flutterMode": "release", + "args": ["--dart-define-from-file=.env"] + } + ] +} diff --git a/README.md b/README.md index 6741da8d..920cda4d 100644 --- a/README.md +++ b/README.md @@ -85,11 +85,17 @@ For a more detailed overview, visit [frostyapp.io](https://www.frostyapp.io/). 3. Go to the [Twitch dev console](https://dev.twitch.tv/login) and register a new application to retrieve a **Client ID** and **Client Secret**. -4. Use [`--dart-define`](https://dartcode.org/docs/using-dart-define-in-flutter/) to set the `clientId` and `secret` environment variables with your **Client ID** and **Client Secret**. +4. Copy `.env.example` to `.env` and fill in your credentials: + + ```bash + cp .env.example .env + ``` 5. Run `flutter pub get` to fetch all the dependencies. -6. Choose an emulator or device and run the app! +6. Choose an emulator or device and run the app! The included VS Code launch configurations will automatically read your `.env` file. + +7. (Optional) Run `./scripts/get-twitch-token.sh` to quickly get a user auth token. Long-press the **Anonymous** account tile in the app to log in from your clipboard. > [!IMPORTANT] > Frosty uses [MobX](https://mobx.netlify.app/) for state management. Please refer to the documentation about code generation, otherwise your changes within MobX stores may not be applied. diff --git a/scripts/get-twitch-token.sh b/scripts/get-twitch-token.sh new file mode 100755 index 00000000..18a40fad --- /dev/null +++ b/scripts/get-twitch-token.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# +# Gets a Twitch OAuth user token for emulator testing. +# +# Usage: ./scripts/get-twitch-token.sh +# +# Reads CLIENT_ID and SECRET from .env, env vars, or prompts interactively. +# Opens the Twitch OAuth page in your browser — after you authorize, +# paste the redirect URL back here and the token is copied to your clipboard. +# Then long-press the Anonymous account tile in the app to log in. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" +ENV_FILE="$PROJECT_DIR/.env" + +load_env_var() { + local name="$1" + local current="${!name:-}" + + if [ -n "$current" ]; then + return + fi + + if [ -f "$ENV_FILE" ] && grep -q "^${name}=" "$ENV_FILE"; then + eval "$name=$(grep "^${name}=" "$ENV_FILE" | cut -d= -f2-)" + return + fi + + read -rp "$name: " "$name" +} + +load_env_var CLIENT_ID +load_env_var SECRET + +if [ -z "${CLIENT_ID:-}" ] || [ -z "${SECRET:-}" ]; then + echo "Error: CLIENT_ID and SECRET are both required." + echo "Add them to .env or export them in your shell." + exit 1 +fi + +SCOPES="chat:read+chat:edit+user:read:follows+user:read:blocked_users+user:manage:blocked_users+user:manage:chat_color" +REDIRECT_URI="https://twitch.tv/login" + +URL="https://id.twitch.tv/oauth2/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=${SCOPES}&force_verify=true" + +echo "Opening Twitch authorization in your browser..." +open "$URL" + +echo "" +echo "After authorizing, copy the full URL from the address bar and paste it here:" +echo "(it will look like https://twitch.tv/login?code=...)" +echo "" +read -rp "> " REDIRECT_URL + +# Extract the authorization code from the redirect URL query params +CODE=$(echo "$REDIRECT_URL" | sed -n 's/.*[?&]code=\([^&]*\).*/\1/p') + +if [ -z "$CODE" ]; then + echo "" + echo "Error: could not extract code from that URL." + echo "Make sure you pasted the full URL including the ?code=... part." + exit 1 +fi + +# Exchange the authorization code for an access token +echo "" +echo "Exchanging code for token..." + +RESPONSE=$(curl -s -X POST "https://id.twitch.tv/oauth2/token" \ + -d "client_id=${CLIENT_ID}" \ + -d "client_secret=${SECRET}" \ + -d "code=${CODE}" \ + -d "grant_type=authorization_code" \ + -d "redirect_uri=${REDIRECT_URI}") + +# Try to extract access_token from JSON response +TOKEN=$(echo "$RESPONSE" | grep -o '"access_token":"[^"]*"' | cut -d'"' -f4) + +if [ -z "$TOKEN" ]; then + echo "Error: token exchange failed." + echo "$RESPONSE" + exit 1 +fi + +echo "$TOKEN" | tr -d '\n' | pbcopy + +echo "Token copied to clipboard!" +echo "" +echo "Now in the emulator, long-press the Anonymous account tile to log in."