commit f87fe06255301fe333d1aa36b7c9a207f3e305dc Author: --repo <--repo> Date: Fri Feb 6 17:44:51 2026 -0800 Initial commit with requirements diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..cc5c18b --- /dev/null +++ b/.envrc @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +export DIRENV_WARN_TIMEOUT=20s + +eval "$(devenv direnvrc)" + +# `use devenv` supports the same options as the `devenv shell` command. +# +# To silence all output, use `--quiet`. +# +# Example usage: use devenv --quiet --impure --option services.postgres.enable:bool true +use devenv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae49879 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Devenv +.devenv* +devenv.local.nix +devenv.local.yaml + +# direnv +.direnv + +# pre-commit +.pre-commit-config.yaml diff --git a/devenv.lock b/devenv.lock new file mode 100644 index 0000000..37fca86 --- /dev/null +++ b/devenv.lock @@ -0,0 +1,122 @@ +{ + "nodes": { + "devenv": { + "locked": { + "dir": "src/modules", + "lastModified": 1770399425, + "owner": "cachix", + "repo": "devenv", + "rev": "0f006b2e9f591cc44cf219048b5e33793530403b", + "type": "github" + }, + "original": { + "dir": "src/modules", + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1769939035, + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "a8ca480175326551d6c4121498316261cbb5b260", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762808025, + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "inputs": { + "nixpkgs-src": "nixpkgs-src" + }, + "locked": { + "lastModified": 1770387899, + "owner": "cachix", + "repo": "devenv-nixpkgs", + "rev": "b001fc58b520257a6bb927fc120544cd02f18b56", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "rolling", + "repo": "devenv-nixpkgs", + "type": "github" + } + }, + "nixpkgs-src": { + "flake": false, + "locked": { + "lastModified": 1770169770, + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "aa290c9891fa4ebe88f8889e59633d20cc06a5f2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": [ + "git-hooks" + ] + } + } + }, + "root": "root", + "version": 7 +} diff --git a/devenv.nix b/devenv.nix new file mode 100644 index 0000000..4c2ff06 --- /dev/null +++ b/devenv.nix @@ -0,0 +1,5 @@ +{ pkgs, lib, config, inputs, ... }: + +{ + languages.go.enable = true; +} diff --git a/devenv.yaml b/devenv.yaml new file mode 100644 index 0000000..116a2ad --- /dev/null +++ b/devenv.yaml @@ -0,0 +1,15 @@ +# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json +inputs: + nixpkgs: + url: github:cachix/devenv-nixpkgs/rolling + +# If you're using non-OSS software, you can set allowUnfree to true. +# allowUnfree: true + +# If you're willing to use a package that's vulnerable +# permittedInsecurePackages: +# - "openssl-1.1.1w" + +# If you have more than one devenv you can merge them +#imports: +# - ./backend diff --git a/requirements.md b/requirements.md new file mode 100644 index 0000000..ea5aa3c --- /dev/null +++ b/requirements.md @@ -0,0 +1,41 @@ +We need to create a new Go library that makes it easy to interface with sf-auth and Gin. There should be two components: 1. A middleware, 2. a prebuilt route. A sample of the Rust implementation looks like the following + +``` +use axum::{ + Router, response::Html, routing::get +}; +use sf_auth_middleware_axum::{SfAuthLayer, SfUser}; +use tower_sessions::{MemoryStore, SessionManagerLayer}; + +async fn root() -> Html { + Html(format!("

Auth demo

Check my info")) +} + +async fn user_info(user: SfUser) -> Html { + Html(format!("

Hello!


Username: {}
User ID: {}", user.username(), user.user_id())) +} + +#[tokio::main] +async fn main() { + tracing_subscriber::fmt::init(); + + let session_store = MemoryStore::default(); + let session_layer = SessionManagerLayer::new(session_store); + + let app = Router::new() + .route("/user_info", get(user_info)) + .layer(SfAuthLayer::new(|_req| "http://localhost:3000/auth_callback".to_string())) + .route("/auth_callback", get(sf_auth_middleware_axum::create_auth_callback("/user_info"))) + .route("/", get(root)) + .layer(session_layer); + + let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); + axum::serve(listener, app).await.unwrap(); +} +``` + +Middleware +The middleware should check the session for an sf_user_id or sf_username. If they are missing, then we should redirect to https://snazzyfellas.com/api/redirect/authenticate?redirect_uri=%s where %s is some URL provided by the user of this library. The user should configure this URL to match the pre-built route in the next section. + +Pre-built Route +There should be a pre-built route that the user of the library can add to their Gin project that lets them handle the callback from the sf-auth api mentioned previously. It should also take in a URL that redirects to another page on the current server, and a relative path will work especially for examples. This endpoint should take in user_id, username, and key as query parameters. This key is one time use, and should be sent along with user_id in a POST request to https://snazzyfellas.com/api/redirect/validate . The response will return JSON with a valid boolean value and a string user_id value. If valid is true and user_id matches the user_id passed to the page, then set the username, user_id session variables. If they do not, then show an error. After setting the session variables, redirect to the URL provided by the user.