2024-04-26 21:12:56 +01:00
package main
import (
2024-04-27 10:35:16 +01:00
"crypto/rand"
2024-05-03 19:07:28 +01:00
"crypto/rsa"
2024-04-26 21:12:56 +01:00
"crypto/sha256"
2024-05-03 19:07:28 +01:00
"crypto/x509"
2024-04-26 21:12:56 +01:00
"database/sql"
"encoding/base64"
2024-05-04 16:15:40 +01:00
"encoding/binary"
2024-04-26 21:12:56 +01:00
"encoding/hex"
2024-05-03 19:07:28 +01:00
"encoding/pem"
2024-04-28 21:24:50 +01:00
"errors"
2024-04-26 21:12:56 +01:00
"fmt"
2024-05-03 19:07:28 +01:00
"log"
"math/big"
2024-04-26 21:12:56 +01:00
"os"
"regexp"
"strconv"
"strings"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
_ "github.com/mattn/go-sqlite3"
"github.com/spf13/viper"
"golang.org/x/crypto/scrypt"
)
2024-05-03 19:07:28 +01:00
var (
2024-05-03 20:15:46 +01:00
privateKey * rsa . PrivateKey
publicKey * rsa . PublicKey
2024-05-03 19:07:28 +01:00
modulus * big . Int
exponent int
)
2024-05-04 16:15:40 +01:00
func Int64ToBase64 ( num int64 ) ( string , error ) {
numBytes := make ( [ ] byte , 8 )
binary . BigEndian . PutUint64 ( numBytes , uint64 ( num ) )
startIndex := 0
for startIndex < len ( numBytes ) && numBytes [ startIndex ] == 0 {
startIndex ++
}
trimmedBytes := numBytes [ startIndex : ]
encoded := base64 . StdEncoding . EncodeToString ( trimmedBytes )
return encoded , nil
2024-05-03 20:38:08 +01:00
}
2024-05-04 16:15:40 +01:00
const salt_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
2024-04-26 21:12:56 +01:00
func genSalt ( length int ) string {
if length <= 0 {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Known in genSalt() at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , "Salt length must be at least one." )
2024-04-26 21:12:56 +01:00
}
salt := make ( [ ] byte , length )
2024-04-27 10:35:16 +01:00
randomBytes := make ( [ ] byte , length )
_ , err := rand . Read ( randomBytes )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in genSalt() at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-27 10:35:16 +01:00
}
2024-04-26 21:12:56 +01:00
for i := range salt {
2024-04-28 21:24:50 +01:00
salt [ i ] = salt_chars [ int ( randomBytes [ i ] ) % len ( salt_chars ) ]
2024-04-26 21:12:56 +01:00
}
return string ( salt )
}
func sha256Base64 ( s string ) string {
hashed := sha256 . Sum256 ( [ ] byte ( s ) )
encoded := base64 . URLEncoding . EncodeToString ( hashed [ : ] )
encoded = strings . TrimRight ( encoded , "=" )
return encoded
}
func hash ( password , salt string ) string {
passwordBytes := [ ] byte ( password )
saltBytes := [ ] byte ( salt )
derivedKey , _ := scrypt . Key ( passwordBytes , saltBytes , 32768 , 8 , 1 , 64 )
hashString := fmt . Sprintf ( "scrypt:32768:8:1$%s$%s" , salt , hex . EncodeToString ( derivedKey ) )
return hashString
}
2024-04-29 00:59:33 +01:00
func verifyHash ( werkzeug_hash , password string ) bool {
parts := strings . Split ( werkzeug_hash , "$" )
2024-04-26 21:12:56 +01:00
if len ( parts ) != 3 || parts [ 0 ] != "scrypt:32768:8:1" {
return false
}
salt := parts [ 1 ]
computedHash := hash ( password , salt )
2024-04-29 00:59:33 +01:00
return werkzeug_hash == computedHash
2024-04-26 21:12:56 +01:00
}
func get_db_connection ( ) * sql . DB {
db , _ := sql . Open ( "sqlite3" , "database.db" )
return db
}
2024-05-03 19:07:28 +01:00
func get_user ( id int ) ( string , string , string , string , bool ) {
norows := false
2024-04-26 21:12:56 +01:00
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in get_user() defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
norows = true
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-05-03 19:07:28 +01:00
var created , username , password , uniqueid string
err := conn . QueryRow ( "SELECT created, username, uniqueid, password FROM users WHERE id = ? LIMIT 1" , id ) . Scan ( & created , & username , & uniqueid , & password )
2024-04-26 21:12:56 +01:00
if err != nil {
2024-04-28 21:24:50 +01:00
if errors . Is ( err , sql . ErrNoRows ) {
2024-04-26 21:12:56 +01:00
norows = true
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in get_user() at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
}
}
2024-05-03 19:07:28 +01:00
return created , username , password , uniqueid , norows
2024-04-26 21:12:56 +01:00
}
func get_user_from_session ( session string ) ( int , bool ) {
2024-05-03 19:07:28 +01:00
norows := false
2024-04-26 21:12:56 +01:00
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in get_user_from_session() defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
norows = true
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
var id int
err := conn . QueryRow ( "SELECT id FROM sessions WHERE session = ? LIMIT 1" , session ) . Scan ( & id )
if err != nil {
2024-04-28 21:24:50 +01:00
if errors . Is ( err , sql . ErrNoRows ) {
2024-04-26 21:12:56 +01:00
norows = true
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in get_user_from_session() at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
}
}
return id , norows
}
func check_username_taken ( username string ) ( int , bool ) {
2024-05-03 19:07:28 +01:00
norows := false
2024-04-26 21:12:56 +01:00
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in check_username_taken() defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
norows = true
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
var id int
err := conn . QueryRow ( "SELECT id FROM users WHERE lower(username) = ? LIMIT 1" , username ) . Scan ( & id )
if err != nil {
2024-04-28 21:24:50 +01:00
if errors . Is ( err , sql . ErrNoRows ) {
2024-04-26 21:12:56 +01:00
norows = true
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in get_user() at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
}
}
return id , norows
}
func init_db ( ) {
if _ , err := os . Stat ( "database.db" ) ; os . IsNotExist ( err ) {
if err := generateDB ( ) ; err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown while generating database at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
return
}
} else {
2024-05-03 19:07:28 +01:00
log . Print ( "Proceeding will overwrite the database. Proceed? (y/n) " )
2024-04-26 21:12:56 +01:00
var answer string
2024-04-28 21:24:50 +01:00
_ , err := fmt . Scanln ( & answer )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown while scanning input at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
return
}
2024-04-26 21:12:56 +01:00
if answer == "y" || answer == "Y" {
if err := generateDB ( ) ; err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown while generating database at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
return
}
} else if answer == ":3" {
2024-05-03 19:07:28 +01:00
log . Println ( "[:3] :3" )
2024-04-26 21:12:56 +01:00
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[INFO] Stopped" )
2024-04-26 21:12:56 +01:00
}
}
}
func generateDB ( ) error {
db , err := sql . Open ( "sqlite3" , "database.db" )
if err != nil {
return err
}
2024-04-28 21:24:50 +01:00
defer func ( db * sql . DB ) {
err := db . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in generateDB() defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
return
2024-04-28 21:24:50 +01:00
}
} ( db )
2024-04-26 21:12:56 +01:00
2024-04-27 10:35:16 +01:00
schemaBytes , err := os . ReadFile ( "schema.sql" )
2024-04-26 21:12:56 +01:00
if err != nil {
return err
}
_ , err = db . Exec ( string ( schemaBytes ) )
if err != nil {
return err
}
2024-05-03 19:07:28 +01:00
log . Println ( "[INFO] Generated database" )
2024-04-26 21:12:56 +01:00
return nil
}
func main ( ) {
if len ( os . Args ) > 1 {
if os . Args [ 1 ] == "init_db" {
init_db ( )
os . Exit ( 0 )
}
}
if _ , err := os . Stat ( "config.ini" ) ; err == nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[INFO] Config loaded at" , time . Now ( ) . Unix ( ) )
2024-04-26 21:12:56 +01:00
} else if os . IsNotExist ( err ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[FATAL] config.ini does not exist" )
2024-04-26 21:12:56 +01:00
os . Exit ( 1 )
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[FATAL] File is in quantumn uncertainty:" , err )
2024-04-26 21:12:56 +01:00
os . Exit ( 1 )
}
viper . SetConfigName ( "config" )
viper . AddConfigPath ( "./" )
viper . AutomaticEnv ( )
2024-05-03 19:07:28 +01:00
err := viper . ReadInConfig ( )
if err != nil {
log . Println ( "[FATAL] Error in config file at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
os . Exit ( 1 )
}
HOST := viper . GetString ( "config.HOST" )
PORT := viper . GetInt ( "config.PORT" )
SECRET_KEY := viper . GetString ( "config.SECRET_KEY" )
2024-05-03 19:07:28 +01:00
PUBLIC_KEY_PATH := viper . GetString ( "config.PUBLIC_KEY" )
PRIVATE_KEY_PATH := viper . GetString ( "config.PRIVATE_KEY" )
2024-04-26 21:12:56 +01:00
if SECRET_KEY == "supersecretkey" {
2024-05-03 19:07:28 +01:00
log . Println ( "[WARNING] Secret key not set. Please set the secret key to a non-default value." )
}
2024-05-03 20:15:46 +01:00
privKeyFile , err := os . ReadFile ( PRIVATE_KEY_PATH )
2024-05-03 19:07:28 +01:00
if err != nil {
log . Fatal ( "[ERROR] Cannot read private key:" , err )
}
2024-05-03 20:15:46 +01:00
block , _ := pem . Decode ( privKeyFile )
if block == nil {
log . Fatal ( "[ERROR] Failed to parse PEM block containing the private key" )
}
2024-05-03 20:18:45 +01:00
privKey , err := x509 . ParsePKCS8PrivateKey ( block . Bytes )
2024-05-03 20:15:46 +01:00
if err != nil {
log . Fatal ( "[ERROR] Failed to parse private key:" , err )
}
2024-05-03 20:18:45 +01:00
var ok bool
privateKey , ok = privKey . ( * rsa . PrivateKey )
if ! ok {
log . Fatal ( "[ERROR] Failed to convert private key to RSA private key" )
}
2024-05-03 20:15:46 +01:00
pubKeyFile , err := os . ReadFile ( PUBLIC_KEY_PATH )
2024-05-03 19:07:28 +01:00
if err != nil {
log . Fatal ( "[ERROR] Cannot read public key:" , err )
}
2024-05-03 20:15:46 +01:00
block , _ = pem . Decode ( pubKeyFile )
2024-05-03 19:07:28 +01:00
if block == nil {
log . Fatal ( "[ERROR] Failed to parse PEM block containing the public key" )
}
pubKey , err := x509 . ParsePKIXPublicKey ( block . Bytes )
if err != nil {
log . Fatal ( "[ERROR] Failed to parse public key:" , err )
}
2024-05-03 20:15:46 +01:00
publicKey , ok = pubKey . ( * rsa . PublicKey )
2024-05-03 19:07:28 +01:00
if ! ok {
log . Fatal ( "[ERROR] Failed to convert public key to RSA public key" )
2024-04-26 21:12:56 +01:00
}
2024-05-03 20:15:46 +01:00
modulus = publicKey . N
exponent = publicKey . E
2024-05-03 19:07:28 +01:00
2024-04-26 21:12:56 +01:00
gin . SetMode ( gin . ReleaseMode )
router := gin . New ( )
2024-04-28 10:55:38 +01:00
// Enable CORS
router . Use ( func ( c * gin . Context ) {
c . Writer . Header ( ) . Set ( "Access-Control-Allow-Origin" , "*" )
c . Writer . Header ( ) . Set ( "Access-Control-Allow-Headers" , "*" )
c . Writer . Header ( ) . Set ( "Access-Control-Allow-Methods" , "*" )
// Handle preflight requests
if c . Request . Method == "OPTIONS" {
c . AbortWithStatus ( 200 )
return
}
c . Next ( )
} )
2024-04-26 21:12:56 +01:00
router . Static ( "/static" , "./static" )
router . LoadHTMLGlob ( "templates/*.html" )
router . GET ( "/" , func ( c * gin . Context ) {
c . Redirect ( 302 , "/login" )
} )
router . GET ( "/login" , func ( c * gin . Context ) {
c . HTML ( 200 , "login.html" , gin . H { } )
} )
router . GET ( "/signup" , func ( c * gin . Context ) {
c . HTML ( 200 , "signup.html" , gin . H { } )
} )
router . GET ( "/logout" , func ( c * gin . Context ) {
c . HTML ( 200 , "logout.html" , gin . H { } )
} )
router . GET ( "/app" , func ( c * gin . Context ) {
c . HTML ( 200 , "main.html" , gin . H { } )
} )
router . GET ( "/dashboard" , func ( c * gin . Context ) {
c . HTML ( 200 , "dashboard.html" , gin . H { } )
} )
2024-04-29 01:45:22 +01:00
router . GET ( "/aeskeyshare" , func ( c * gin . Context ) {
2024-04-29 21:23:15 +01:00
c . HTML ( 200 , "aeskeyshare.html" , gin . H { } )
2024-04-29 01:45:22 +01:00
} )
2024-04-26 21:12:56 +01:00
router . GET ( "/.well-known/openid-configuration" , func ( c * gin . Context ) {
c . HTML ( 200 , "openid.html" , gin . H { } )
} )
router . GET ( "/api/version" , func ( c * gin . Context ) {
c . String ( 200 , "Burgerauth Version 1.3" )
} )
router . POST ( "/api/signup" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
username := data [ "username" ] . ( string )
password := data [ "password" ] . ( string )
if username == "" || password == "" || len ( username ) > 20 || ! regexp . MustCompile ( "^[a-zA-Z0-9]+$" ) . MatchString ( username ) {
c . JSON ( 422 , gin . H { "error" : "Invalid username or password" } )
return
}
_ , norows := check_username_taken ( username )
if ! norows {
c . JSON ( 409 , gin . H { "error" : "Username taken" } )
return
}
hashedPassword := hash ( password , genSalt ( 16 ) )
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/signup defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
2024-04-28 21:24:50 +01:00
_ , err = conn . Exec ( "INSERT INTO users (username, password, created, uniqueid) VALUES (?, ?, ?, ?)" , username , hashedPassword , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) , genSalt ( 512 ) )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/signup user creation at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
return
}
2024-05-03 19:07:28 +01:00
log . Println ( "[INFO] Added new user at" , time . Now ( ) . Unix ( ) )
2024-04-26 21:12:56 +01:00
userid , _ := check_username_taken ( username )
randomchars := genSalt ( 512 )
2024-04-28 21:24:50 +01:00
_ , err = conn . Exec ( "INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)" , randomchars , userid , c . Request . Header . Get ( "User-Agent" ) )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/signup session creation at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
return
}
2024-04-26 21:12:56 +01:00
c . JSON ( 200 , gin . H { "key" : randomchars } )
} )
router . POST ( "/api/login" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
username := data [ "username" ] . ( string )
password := data [ "password" ] . ( string )
passwordchange := data [ "password" ] . ( string )
newpass := data [ "password" ] . ( string )
userid , norows := check_username_taken ( username )
if norows {
c . JSON ( 401 , gin . H { "error" : "User does not exist" } )
return
}
2024-05-03 19:07:28 +01:00
_ , _ , userpassword , _ , _ := get_user ( userid )
2024-04-26 21:12:56 +01:00
if ! verifyHash ( userpassword , password ) {
c . JSON ( 401 , gin . H { "error" : "Incorrect password" } )
return
}
randomchars := genSalt ( 512 )
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/login defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
2024-04-28 21:24:50 +01:00
_ , err = conn . Exec ( "INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)" , randomchars , userid , c . Request . Header . Get ( "User-Agent" ) )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/login session creation at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
return
}
2024-04-26 21:12:56 +01:00
if passwordchange == "yes" {
hashpassword := hash ( newpass , "" )
2024-04-28 21:24:50 +01:00
_ , err = conn . Exec ( "UPDATE users SET password = ? WHERE username = ?" , hashpassword , username )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/login password change at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
return
}
2024-04-26 21:12:56 +01:00
}
c . JSON ( 200 , gin . H { "key" : randomchars } )
} )
router . POST ( "/api/userinfo" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
secretkey := data [ "secretKey" ] . ( string )
userid , norows := get_user_from_session ( secretkey )
if norows {
c . JSON ( 400 , gin . H { "error" : "Session does not exist" } )
return
}
2024-05-03 19:07:28 +01:00
created , username , _ , _ , norows := get_user ( userid )
2024-04-26 21:12:56 +01:00
if norows {
c . JSON ( 400 , gin . H { "error" : "User does not exist" } )
return
}
c . JSON ( 200 , gin . H { "username" : username , "id" : userid , "created" : created } )
} )
router . GET ( "/userinfo" , func ( c * gin . Context ) {
2024-04-28 10:45:58 +01:00
token := strings . Fields ( c . Request . Header [ "Authorization" ] [ 0 ] ) [ 1 ]
2024-04-26 21:12:56 +01:00
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /userinfo defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-28 10:45:58 +01:00
var blacklisted bool
err := conn . QueryRow ( "SELECT blacklisted FROM blacklist WHERE openid = ? LIMIT 1" , token ) . Scan ( & blacklisted )
if err == nil {
c . JSON ( 400 , gin . H { "error" : "Token is in blacklist" } )
return
} else {
2024-04-28 21:24:50 +01:00
if ! errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /userinfo blacklist at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 10:45:58 +01:00
return
}
}
parsedtoken , err := jwt . Parse ( token , func ( token * jwt . Token ) ( interface { } , error ) {
2024-05-03 19:07:28 +01:00
return publicKey , nil
2024-04-28 10:45:58 +01:00
} )
if err != nil {
c . JSON ( 401 , gin . H { "error" : "Malformed token" } )
return
}
var claims jwt . MapClaims
var ok bool
if parsedtoken . Valid {
claims , ok = parsedtoken . Claims . ( jwt . MapClaims )
if ! ok {
c . JSON ( 401 , gin . H { "error" : "Invalid token claims" } )
return
}
}
session := claims [ "session" ] . ( string )
2024-04-28 11:20:54 +01:00
exp := claims [ "exp" ] . ( float64 )
if int64 ( exp ) < time . Now ( ) . Unix ( ) {
2024-04-28 10:45:58 +01:00
c . JSON ( 403 , gin . H { "error" : "Expired token" } )
return
}
userid , norows := get_user_from_session ( session )
if norows {
c . JSON ( 400 , gin . H { "error" : "Session does not exist" } )
return
}
2024-04-26 21:12:56 +01:00
2024-05-03 19:07:28 +01:00
_ , username , _ , uniqueid , norows := get_user ( userid )
2024-04-26 21:12:56 +01:00
if norows {
c . JSON ( 400 , gin . H { "error" : "User does not exist" } )
return
}
2024-05-03 19:07:28 +01:00
user := gin . H { "name" : username }
c . JSON ( 200 , gin . H { "sub" : uniqueid , "user" : user } )
2024-04-26 21:12:56 +01:00
} )
2024-04-28 10:45:58 +01:00
router . POST ( "/api/uniqueid" , func ( c * gin . Context ) {
2024-04-28 11:01:04 +01:00
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-28 10:45:58 +01:00
2024-04-28 11:01:04 +01:00
token := data [ "access_token" ] . ( string )
2024-04-28 10:45:58 +01:00
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/uniqueid defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-28 10:45:58 +01:00
var blacklisted bool
2024-04-28 21:24:50 +01:00
err = conn . QueryRow ( "SELECT blacklisted FROM blacklist WHERE token = ? LIMIT 1" , token ) . Scan ( & blacklisted )
2024-04-28 10:45:58 +01:00
if err == nil {
c . JSON ( 400 , gin . H { "error" : "Token is in blacklist" } )
return
} else {
2024-04-28 21:24:50 +01:00
if ! errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/uniqueid blacklist at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
return
}
}
parsedtoken , err := jwt . Parse ( token , func ( token * jwt . Token ) ( interface { } , error ) {
return publicKey , nil
} )
if err != nil {
c . JSON ( 401 , gin . H { "error" : "Malformed token" } )
return
}
var claims jwt . MapClaims
var ok bool
if parsedtoken . Valid {
claims , ok = parsedtoken . Claims . ( jwt . MapClaims )
if ! ok {
c . JSON ( 401 , gin . H { "error" : "Invalid token claims" } )
2024-04-28 10:45:58 +01:00
return
}
}
2024-05-03 19:07:28 +01:00
session := claims [ "session" ] . ( string )
exp := claims [ "exp" ] . ( float64 )
if int64 ( exp ) < time . Now ( ) . Unix ( ) {
c . JSON ( 403 , gin . H { "error" : "Expired token" } )
return
}
userid , norows := get_user_from_session ( session )
if norows {
c . JSON ( 400 , gin . H { "error" : "Session does not exist" } )
return
}
_ , _ , _ , uniqueid , norows := get_user ( userid )
if norows {
c . JSON ( 400 , gin . H { "error" : "User does not exist" } )
return
}
c . JSON ( 200 , gin . H { "uniqueid" : uniqueid } )
2024-04-29 00:59:33 +01:00
} )
router . POST ( "/api/loggedin" , func ( c * gin . Context ) {
var data map [ string ] interface { }
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
token := data [ "access_token" ] . ( string )
conn := get_db_connection ( )
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/uniqueid defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-29 00:59:33 +01:00
}
} ( conn )
var blacklisted bool
err = conn . QueryRow ( "SELECT blacklisted FROM blacklist WHERE token = ? LIMIT 1" , token ) . Scan ( & blacklisted )
if err == nil {
c . JSON ( 400 , gin . H { "error" : "Token is in blacklist" } )
return
} else {
if ! errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/uniqueid blacklist at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-29 00:59:33 +01:00
return
}
}
2024-04-28 10:45:58 +01:00
parsedtoken , err := jwt . Parse ( token , func ( token * jwt . Token ) ( interface { } , error ) {
2024-05-03 19:07:28 +01:00
return publicKey , nil
2024-04-28 10:45:58 +01:00
} )
if err != nil {
c . JSON ( 401 , gin . H { "error" : "Malformed token" } )
return
}
var claims jwt . MapClaims
var ok bool
if parsedtoken . Valid {
claims , ok = parsedtoken . Claims . ( jwt . MapClaims )
if ! ok {
c . JSON ( 401 , gin . H { "error" : "Invalid token claims" } )
return
}
}
session := claims [ "session" ] . ( string )
2024-04-28 11:20:54 +01:00
exp := claims [ "exp" ] . ( float64 )
if int64 ( exp ) < time . Now ( ) . Unix ( ) {
2024-04-28 10:45:58 +01:00
c . JSON ( 403 , gin . H { "error" : "Expired token" } )
return
}
2024-04-29 00:59:33 +01:00
_ , norows := get_user_from_session ( session )
2024-04-28 10:45:58 +01:00
if norows {
c . JSON ( 400 , gin . H { "error" : "Session does not exist" } )
return
}
2024-04-29 00:59:33 +01:00
c . JSON ( 200 , gin . H { "success" : "true" } )
2024-04-28 10:45:58 +01:00
} )
2024-04-26 21:12:56 +01:00
router . GET ( "/api/auth" , func ( c * gin . Context ) {
secretKey , _ := c . Cookie ( "key" )
appId := c . Request . URL . Query ( ) . Get ( "client_id" )
code := c . Request . URL . Query ( ) . Get ( "code_challenge" )
codemethod := c . Request . URL . Query ( ) . Get ( "code_challenge_method" )
redirect_uri := c . Request . URL . Query ( ) . Get ( "redirect_uri" )
state := c . Request . URL . Query ( ) . Get ( "state" )
userid , norows := get_user_from_session ( secretKey )
if norows {
c . String ( 400 , "Session does not exist" )
return
}
2024-05-03 19:07:28 +01:00
_ , username , _ , _ , norows := get_user ( userid )
2024-04-26 21:12:56 +01:00
if norows {
c . String ( 400 , "User does not exist" )
return
}
conn := get_db_connection ( )
var appidcheck , rdiruricheck string
2024-04-28 21:24:50 +01:00
err := conn . QueryRow ( "SELECT appId, rdiruri FROM oauth WHERE appId = ? LIMIT 1" , appId ) . Scan ( & appidcheck , & rdiruricheck )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
c . String ( 401 , "OAuth screening failed" )
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/auth at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
}
return
}
2024-04-26 21:12:56 +01:00
2024-04-26 21:39:57 +01:00
if ! ( rdiruricheck == redirect_uri ) {
2024-04-26 21:12:56 +01:00
c . String ( 401 , "Redirect URI does not match" )
return
}
if ! ( appidcheck == appId ) {
c . String ( 401 , "OAuth screening failed" )
return
}
datatemplate := jwt . MapClaims {
"sub" : username ,
2024-04-26 21:15:43 +01:00
"iss" : "https://auth.hectabit.org" ,
2024-04-26 21:12:56 +01:00
"name" : username ,
"aud" : appId ,
"exp" : time . Now ( ) . Unix ( ) + 2592000 ,
"iat" : time . Now ( ) . Unix ( ) ,
"auth_time" : time . Now ( ) . Unix ( ) ,
2024-04-28 10:45:58 +01:00
"session" : secretKey ,
2024-04-26 21:12:56 +01:00
"nonce" : genSalt ( 512 ) ,
}
datatemplate2 := jwt . MapClaims {
2024-04-28 10:45:58 +01:00
"exp" : time . Now ( ) . Unix ( ) + 2592000 ,
"iat" : time . Now ( ) . Unix ( ) ,
"session" : secretKey ,
"nonce" : genSalt ( 512 ) ,
2024-04-26 21:12:56 +01:00
}
2024-05-03 19:07:28 +01:00
jwt_token , err := jwt . NewWithClaims ( jwt . SigningMethodRS256 , datatemplate ) . SignedString ( privateKey )
if err != nil {
log . Println ( "[ERROR] Unknown in /api/auth jwt_token at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: jwt_token_cannotsign." )
return
}
secret_token , err := jwt . NewWithClaims ( jwt . SigningMethodRS256 , datatemplate2 ) . SignedString ( privateKey )
if err != nil {
log . Println ( "[ERROR] Unknown in /api/auth secret_token at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: jwt_token_cannotsign_secret." )
return
}
2024-04-26 21:12:56 +01:00
randombytes := genSalt ( 512 )
2024-04-28 21:24:50 +01:00
_ , err = conn . Exec ( "INSERT INTO logins (appId, secret, nextsecret, code, nextcode, creator, openid, nextopenid, pkce, pkcemethod) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" , appId , randombytes , "none" , secret_token , "none" , userid , jwt_token , "none" , code , codemethod )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/auth insert at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_insert_auth." )
2024-04-28 21:24:50 +01:00
return
}
2024-04-26 21:12:56 +01:00
if randombytes != "" {
c . Redirect ( 302 , redirect_uri + "?code=" + randombytes + "&state=" + state )
} else {
2024-05-03 19:07:28 +01:00
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: secretkey_not_found." )
log . Println ( "[ERROR] Secretkey not found at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) )
2024-04-26 21:12:56 +01:00
}
} )
router . POST ( "/api/tokenauth" , func ( c * gin . Context ) {
2024-04-28 21:24:50 +01:00
err := c . Request . ParseForm ( )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid form data" } )
return
}
2024-04-26 21:12:56 +01:00
data := c . Request . Form
appId := data . Get ( "client_id" )
code := data . Get ( "code" )
code_verify := data . Get ( "code_verifier" )
secret := data . Get ( "client_secret" )
var verifycode bool
if code_verify == "" {
verifycode = false
2024-04-26 21:39:57 +01:00
} else {
verifycode = true
2024-04-26 21:12:56 +01:00
}
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/tokenauth defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
var appidcheck , secretcheck , openid , logincode , pkce , pkcemethod string
2024-04-28 21:24:50 +01:00
err = conn . QueryRow ( "SELECT o.appId, o.secret, l.openid, l.code, l.pkce, l.pkcemethod FROM oauth AS o JOIN logins AS l ON o.appId = l.appId WHERE o.appId = ? AND l.secret = ? LIMIT 1;" , appId , code ) . Scan ( & appidcheck , & secretcheck , & openid , & logincode , & pkce , & pkcemethod )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
c . JSON ( 401 , gin . H { "error" : "OAuth screening failed" } )
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/tokenauth at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
}
return
}
2024-04-26 21:12:56 +01:00
if appidcheck != appId {
c . JSON ( 401 , gin . H { "error" : "OAuth screening failed" } )
return
}
if verifycode {
if pkce == "none" {
c . JSON ( 400 , gin . H { "error" : "Attempted PKCE exchange with non-PKCE authentication" } )
return
} else {
if pkcemethod == "S256" {
if sha256Base64 ( code_verify ) != pkce {
c . JSON ( 403 , gin . H { "error" : "Invalid PKCE code" } )
return
}
} else if pkcemethod == "plain" {
if code_verify != pkce {
c . JSON ( 403 , gin . H { "error" : "Invalid PKCE code" } )
return
}
} else {
c . JSON ( 403 , gin . H { "error" : "Attempted PKCE exchange without supported PKCE token method" } )
return
}
}
} else {
if secret != secretcheck {
c . JSON ( 401 , gin . H { "error" : "Invalid secret" } )
return
}
}
2024-04-28 21:24:50 +01:00
_ , err = conn . Exec ( "DELETE FROM logins WHERE code = ?" , logincode )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/tokenauth delete at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
return
}
2024-04-28 10:45:58 +01:00
2024-05-04 16:15:40 +01:00
c . JSON ( 200 , gin . H { "access_token" : logincode , "token_type" : "bearer" , "expires_in" : 2592000 , "id_token" : openid } )
2024-04-26 21:12:56 +01:00
} )
router . POST ( "/api/deleteauth" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
secretKey := data [ "secretKey" ] . ( string )
appId := data [ "appId" ] . ( string )
id , norows := get_user_from_session ( secretKey )
if norows {
c . JSON ( 401 , gin . H { "error" : "User does not exist" } )
return
}
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/deleteauth defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
_ , err = conn . Exec ( "DELETE FROM oauth WHERE appId = ? AND creator = ?" , appId , id )
2024-04-26 21:12:56 +01:00
if err != nil {
2024-04-28 21:24:50 +01:00
if errors . Is ( err , sql . ErrNoRows ) {
2024-04-26 21:12:56 +01:00
c . JSON ( 400 , gin . H { "error" : "AppID Not found" } )
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/deleteauth at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
} else {
c . JSON ( 200 , gin . H { "success" : "true" } )
}
} )
router . POST ( "/api/newauth" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
secretKey := data [ "secretKey" ] . ( string )
appId := data [ "appId" ] . ( string )
rdiruri := data [ "rdiruri" ] . ( string )
id , norows := get_user_from_session ( secretKey )
if norows {
c . JSON ( 400 , gin . H { "error" : "User does not exist" } )
return
}
var testsecret string
secret := genSalt ( 512 )
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/newauth defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
for {
err := conn . QueryRow ( "SELECT secret FROM oauth WHERE secret = ?" , secret ) . Scan ( & testsecret )
if err != nil {
2024-04-28 21:24:50 +01:00
if errors . Is ( err , sql . ErrNoRows ) {
2024-04-26 21:12:56 +01:00
break
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/newauth secretselect at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
return
}
} else {
secret = genSalt ( 512 )
}
}
2024-04-28 21:24:50 +01:00
_ , err = conn . Exec ( "SELECT secret FROM oauth WHERE appId = ?" , appId )
2024-04-26 21:12:56 +01:00
if err != nil {
2024-04-28 21:24:50 +01:00
if errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[Info] New Oauth source added with ID:" , appId )
2024-04-26 21:12:56 +01:00
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/newauth at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
return
}
} else {
secret = genSalt ( 512 )
}
2024-04-28 21:24:50 +01:00
_ , err = conn . Exec ( "INSERT INTO oauth (appId, creator, secret, rdiruri) VALUES (?, ?, ?, ?)" , appId , id , secret , rdiruri )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/newauth insert at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
return
}
2024-04-26 21:12:56 +01:00
c . JSON ( 200 , gin . H { "key" : secret } )
} )
router . POST ( "/api/listauth" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
secretKey := data [ "secretKey" ] . ( string )
id , norows := get_user_from_session ( secretKey )
if norows {
c . JSON ( 401 , gin . H { "error" : "User does not exist" } )
return
}
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/listauth defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
rows , err := conn . Query ( "SELECT appId FROM oauth WHERE creator = ? ORDER BY creator DESC" , id )
if err != nil {
c . JSON ( 500 , gin . H { "error" : "Failed to query database" } )
return
}
2024-04-28 21:24:50 +01:00
defer func ( rows * sql . Rows ) {
err := rows . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/listauth rows close at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
}
} ( rows )
2024-04-26 21:12:56 +01:00
var datatemplate [ ] map [ string ] interface { }
for rows . Next ( ) {
var appId string
if err := rows . Scan ( & appId ) ; err != nil {
c . JSON ( 500 , gin . H { "error" : "Failed to scan row" } )
return
}
template := map [ string ] interface { } { "appId" : appId }
datatemplate = append ( datatemplate , template )
}
if err := rows . Err ( ) ; err != nil {
c . JSON ( 500 , gin . H { "error" : "Error iterating over query results" } )
return
}
c . JSON ( 200 , datatemplate )
} )
router . POST ( "/api/deleteaccount" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
secretKey := data [ "secretKey" ] . ( string )
id , norows := get_user_from_session ( secretKey )
if norows {
c . JSON ( 401 , gin . H { "error" : "User does not exist" } )
return
}
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/deleteaccount defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
2024-04-28 21:24:50 +01:00
_ , err = conn . Exec ( "DELETE FROM userdata WHERE creator = ?" , id )
2024-04-26 21:12:56 +01:00
if err != nil {
2024-04-28 21:24:50 +01:00
if ! errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/deleteuser userdata at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
_ , err = conn . Exec ( "DELETE FROM logins WHERE creator = ?" , id )
if err != nil {
2024-04-28 21:24:50 +01:00
if ! errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/deleteuser logins at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
_ , err = conn . Exec ( "DELETE FROM oauth WHERE creator = ?" , id )
if err != nil {
2024-04-28 21:24:50 +01:00
if ! errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/deleteuser oauth at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
_ , err = conn . Exec ( "DELETE FROM users WHERE id = ?" , id )
if err != nil {
2024-04-28 21:24:50 +01:00
if ! errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/deleteuser logins at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
c . JSON ( 200 , gin . H { "success" : "true" } )
} )
router . POST ( "/api/sessions/list" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
secretKey := data [ "secretKey" ] . ( string )
id , norows := get_user_from_session ( secretKey )
if norows {
c . JSON ( 401 , gin . H { "error" : "User does not exist" } )
return
}
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/sessions/list defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
rows , err := conn . Query ( "SELECT sessionid, session, device FROM sessions WHERE id = ? ORDER BY id DESC" , id )
if err != nil {
2024-04-28 21:24:50 +01:00
if ! errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/sessions/list at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
2024-04-28 21:24:50 +01:00
defer func ( rows * sql . Rows ) {
err := rows . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/sessions/list rows close at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
}
} ( rows )
2024-04-26 21:12:56 +01:00
var datatemplate [ ] map [ string ] interface { }
for rows . Next ( ) {
var id , sessionid , device string
thisSession := false
if err := rows . Scan ( & id , & sessionid , & device ) ; err != nil {
c . JSON ( 500 , gin . H { "error" : "Failed to scan row" } )
return
}
if sessionid == secretKey {
thisSession = true
}
template := map [ string ] interface { } { "id" : sessionid , "thisSession" : thisSession , "device" : device }
datatemplate = append ( datatemplate , template )
}
if err := rows . Err ( ) ; err != nil {
c . JSON ( 500 , gin . H { "error" : "Error iterating over query results" } )
return
}
c . JSON ( 200 , datatemplate )
} )
router . POST ( "/api/sessions/remove" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
secretKey := data [ "secretKey" ] . ( string )
sessionId := data [ "sessionId" ] . ( string )
id , norows := get_user_from_session ( secretKey )
if norows {
c . JSON ( 401 , gin . H { "error" : "User does not exist" } )
return
}
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/sessions/remove defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
_ , err = conn . Exec ( "DELETE FROM sessions WHERE sessionid = ? AND id = ?" , sessionId , id )
2024-04-26 21:12:56 +01:00
if err != nil {
2024-04-28 21:24:50 +01:00
if errors . Is ( err , sql . ErrNoRows ) {
2024-04-26 21:12:56 +01:00
c . JSON ( 422 , gin . H { "error" : "SessionID Not found" } )
} else {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/sessions/remove at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
} else {
c . JSON ( 200 , gin . H { "success" : "true" } )
}
} )
router . POST ( "/api/listusers" , func ( c * gin . Context ) {
var data map [ string ] interface { }
2024-04-28 21:24:50 +01:00
err := c . ShouldBindJSON ( & data )
if err != nil {
c . JSON ( 400 , gin . H { "error" : "Invalid JSON" } )
return
}
2024-04-26 21:12:56 +01:00
masterkey := data [ "masterkey" ] . ( string )
if masterkey == SECRET_KEY {
conn := get_db_connection ( )
2024-04-28 21:24:50 +01:00
defer func ( conn * sql . DB ) {
err := conn . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/listusers defer at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . String ( 500 , "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgerauth and refer to the docs for more detail. Include this error code: cannot_close_db." )
return
2024-04-28 21:24:50 +01:00
}
} ( conn )
2024-04-26 21:12:56 +01:00
rows , err := conn . Query ( "SELECT * FROM users ORDER BY id DESC" )
if err != nil {
2024-04-28 21:24:50 +01:00
if ! errors . Is ( err , sql . ErrNoRows ) {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/listusers at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-26 21:12:56 +01:00
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
2024-04-28 21:24:50 +01:00
defer func ( rows * sql . Rows ) {
err := rows . Close ( )
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[ERROR] Unknown in /api/listusers rows close at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
2024-04-28 21:24:50 +01:00
}
} ( rows )
2024-04-26 21:12:56 +01:00
var datatemplate [ ] map [ string ] interface { }
for rows . Next ( ) {
var id , username string
if err := rows . Scan ( & id , & username ) ; err != nil {
c . JSON ( 500 , gin . H { "error" : "Failed to scan row" } )
return
}
template := map [ string ] interface { } { "id" : id , "username" : username }
datatemplate = append ( datatemplate , template )
}
if err := rows . Err ( ) ; err != nil {
c . JSON ( 500 , gin . H { "error" : "Error iterating over query results" } )
return
}
c . JSON ( 200 , datatemplate )
}
} )
2024-05-03 19:07:28 +01:00
router . GET ( "/.well-known/jwks.json" , func ( c * gin . Context ) {
2024-05-04 16:15:40 +01:00
mod , err := Int64ToBase64 ( modulus . Int64 ( ) )
if err != nil {
log . Println ( "[ERROR] Unknown in /well-known/jwks.json modulus at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
return
}
exp , err := Int64ToBase64 ( int64 ( exponent ) )
if err != nil {
log . Println ( "[ERROR] Unknown in /well-known/jwks.json exponent at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
return
}
2024-05-03 19:07:28 +01:00
keys := gin . H {
"keys" : [ ] gin . H {
{
"kty" : "RSA" ,
"alg" : "RS256" ,
"use" : "sig" ,
"kid" : "burgerauth" ,
2024-05-04 16:15:40 +01:00
"n" : mod ,
"e" : exp ,
2024-05-03 19:07:28 +01:00
} ,
} ,
}
c . JSON ( 200 , keys )
} )
log . Println ( "[INFO] Server started at" , time . Now ( ) . Unix ( ) )
log . Println ( "[INFO] Welcome to Burgerauth! Today we are running on IP " + HOST + " on port " + strconv . Itoa ( PORT ) + "." )
err = router . Run ( HOST + ":" + strconv . Itoa ( PORT ) )
2024-04-28 21:24:50 +01:00
if err != nil {
2024-05-03 19:07:28 +01:00
log . Println ( "[FATAL] Server failed to start at" , time . Now ( ) . Unix ( ) , err )
2024-04-28 21:24:50 +01:00
return
}
2024-04-26 21:12:56 +01:00
}