2024-04-26 21:12:56 +01:00
package main
import (
2024-04-27 10:35:16 +01:00
"crypto/rand"
2024-04-26 21:12:56 +01:00
"crypto/sha256"
"database/sql"
"encoding/base64"
"encoding/hex"
"fmt"
"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"
)
const SALT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
func genSalt ( length int ) string {
if length <= 0 {
2024-04-27 10:35:16 +01:00
fmt . 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 {
fmt . Println ( "[ERROR] Unknown in genSalt() at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
}
2024-04-26 21:12:56 +01:00
for i := range salt {
2024-04-27 10:35:16 +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
}
func verifyHash ( werkzeughash , password string ) bool {
parts := strings . Split ( werkzeughash , "$" )
if len ( parts ) != 3 || parts [ 0 ] != "scrypt:32768:8:1" {
return false
}
salt := parts [ 1 ]
computedHash := hash ( password , salt )
return werkzeughash == computedHash
}
func get_db_connection ( ) * sql . DB {
db , _ := sql . Open ( "sqlite3" , "database.db" )
return db
}
func get_user ( id int ) ( string , string , string , bool ) {
conn := get_db_connection ( )
defer conn . Close ( )
var created , username , password string
err := conn . QueryRow ( "SELECT created, username, password FROM users WHERE id = ? LIMIT 1" , id ) . Scan ( & created , & username , & password )
norows := false
if err != nil {
if err == sql . ErrNoRows {
norows = true
} else {
fmt . Println ( "[ERROR] Unknown in get_user() at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
}
}
return created , username , password , norows
}
func get_user_from_session ( session string ) ( int , bool ) {
conn := get_db_connection ( )
defer conn . Close ( )
var id int
err := conn . QueryRow ( "SELECT id FROM sessions WHERE session = ? LIMIT 1" , session ) . Scan ( & id )
norows := false
if err != nil {
if err == sql . ErrNoRows {
norows = true
} else {
fmt . Println ( "[ERROR] Unknown in get_user_from_session() at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
}
}
return id , norows
}
func check_username_taken ( username string ) ( int , bool ) {
conn := get_db_connection ( )
defer conn . Close ( )
var id int
err := conn . QueryRow ( "SELECT id FROM users WHERE lower(username) = ? LIMIT 1" , username ) . Scan ( & id )
norows := false
if err != nil {
if err == sql . ErrNoRows {
norows = true
} else {
fmt . Println ( "[ERROR] Unknown in get_user() at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
}
}
return id , norows
}
func init_db ( ) {
if _ , err := os . Stat ( "database.db" ) ; os . IsNotExist ( err ) {
if err := generateDB ( ) ; err != nil {
fmt . Println ( "[ERROR] Unknown while generating database at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
return
}
} else {
fmt . Print ( "Proceeding will overwrite the database. Proceed? (y/n) " )
var answer string
fmt . Scanln ( & answer )
if answer == "y" || answer == "Y" {
if err := generateDB ( ) ; err != nil {
fmt . Println ( "[ERROR] Unknown while generating database at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
return
}
} else if answer == ":3" {
fmt . Println ( "[:3] :3" )
} else {
fmt . Println ( "[INFO] Stopped" )
}
}
}
func generateDB ( ) error {
db , err := sql . Open ( "sqlite3" , "database.db" )
if err != nil {
return err
}
defer db . Close ( )
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
}
fmt . Println ( "[INFO] Generated database" )
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 {
fmt . Println ( "[INFO] Config loaded at" , time . Now ( ) . Unix ( ) )
} else if os . IsNotExist ( err ) {
fmt . Println ( "[FATAL] config.ini does not exist" )
os . Exit ( 1 )
} else {
fmt . Println ( "[FATAL] File is in quantumn uncertainty:" , err )
os . Exit ( 1 )
}
viper . SetConfigName ( "config" )
viper . AddConfigPath ( "./" )
viper . AutomaticEnv ( )
if err := viper . ReadInConfig ( ) ; err != nil {
fmt . Println ( "[FATAL] Error in config file at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
os . Exit ( 1 )
}
HOST := viper . GetString ( "config.HOST" )
PORT := viper . GetInt ( "config.PORT" )
SECRET_KEY := viper . GetString ( "config.SECRET_KEY" )
if SECRET_KEY == "supersecretkey" {
fmt . Println ( "[WARNING] Secret key not set. Please set the secret key to a non-default value." )
}
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 { } )
} )
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 { }
c . ShouldBindJSON ( & data )
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 ( )
defer conn . Close ( )
2024-04-28 10:45:58 +01:00
conn . Exec ( "INSERT INTO users (username, password, created, uniqueid) VALUES (?, ?, ?, ?)" , username , hashedPassword , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) , genSalt ( 512 ) )
2024-04-26 21:12:56 +01:00
fmt . Println ( "[INFO] Added new user at" , time . Now ( ) . Unix ( ) )
userid , _ := check_username_taken ( username )
randomchars := genSalt ( 512 )
conn . Exec ( "INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)" , randomchars , userid , c . Request . Header . Get ( "User-Agent" ) )
c . JSON ( 200 , gin . H { "key" : randomchars } )
} )
router . POST ( "/api/login" , func ( c * gin . Context ) {
var data map [ string ] interface { }
c . ShouldBindJSON ( & data )
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
}
_ , _ , userpassword , _ := get_user ( userid )
if ! verifyHash ( userpassword , password ) {
c . JSON ( 401 , gin . H { "error" : "Incorrect password" } )
return
}
randomchars := genSalt ( 512 )
conn := get_db_connection ( )
defer conn . Close ( )
conn . Exec ( "INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)" , randomchars , userid , c . Request . Header . Get ( "User-Agent" ) )
if passwordchange == "yes" {
hashpassword := hash ( newpass , "" )
conn . Exec ( "UPDATE users SET password = ? WHERE username = ?" , hashpassword , username )
}
c . JSON ( 200 , gin . H { "key" : randomchars } )
} )
router . POST ( "/api/userinfo" , func ( c * gin . Context ) {
var data map [ string ] interface { }
c . ShouldBindJSON ( & data )
secretkey := data [ "secretKey" ] . ( string )
userid , norows := get_user_from_session ( secretkey )
if norows {
c . JSON ( 400 , gin . H { "error" : "Session does not exist" } )
return
}
created , username , _ , norows := get_user ( userid )
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 ( )
defer conn . Close ( )
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 {
if err != sql . ErrNoRows {
fmt . Println ( "[ERROR] Unknown in /userinfo blacklist at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
return
}
}
parsedtoken , err := jwt . Parse ( token , func ( token * jwt . Token ) ( interface { } , error ) {
return [ ] byte ( SECRET_KEY ) , 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" } )
return
}
}
session := claims [ "session" ] . ( string )
exp := claims [ "exp" ] . ( int64 )
if 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
}
2024-04-26 21:12:56 +01:00
_ , username , _ , norows := get_user ( userid )
if norows {
c . JSON ( 400 , gin . H { "error" : "User does not exist" } )
return
}
c . JSON ( 200 , gin . H { "sub" : username , "name" : username } )
} )
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 { }
c . ShouldBindJSON ( & data )
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 ( )
defer conn . Close ( )
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 err != sql . ErrNoRows {
fmt . 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 [ ] byte ( SECRET_KEY ) , 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" } )
return
}
}
session := claims [ "session" ] . ( string )
exp := claims [ "exp" ] . ( int64 )
if 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
}
var uniqueid string
err = conn . QueryRow ( "SELECT uniqueid FROM users WHERE id = ? LIMIT 1" , userid ) . Scan ( & uniqueid )
if err != nil {
if err == sql . ErrNoRows {
c . JSON ( 400 , gin . H { "error" : "User does not exist" } )
return
} else {
fmt . Println ( "[ERROR] Unknown in /api/uniqueid fetch at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
return
}
}
c . JSON ( 200 , gin . H { "uniqueid" : uniqueid } )
} )
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
}
_ , username , _ , norows := get_user ( userid )
if norows {
c . String ( 400 , "User does not exist" )
return
}
conn := get_db_connection ( )
var appidcheck , rdiruricheck string
conn . QueryRow ( "SELECT appId, rdiruri FROM oauth WHERE appId = ? LIMIT 1" , appId ) . Scan ( & appidcheck , & rdiruricheck )
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
}
jwt_token , _ := jwt . NewWithClaims ( jwt . SigningMethodHS256 , datatemplate ) . SignedString ( [ ] byte ( SECRET_KEY ) )
secret_token , _ := jwt . NewWithClaims ( jwt . SigningMethodHS256 , datatemplate2 ) . SignedString ( [ ] byte ( SECRET_KEY ) )
randombytes := genSalt ( 512 )
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 randombytes != "" {
c . Redirect ( 302 , redirect_uri + "?code=" + randombytes + "&state=" + state )
} else {
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." )
fmt . Println ( "[ERROR] Secretkey not found at" , time . Now ( ) . Unix ( ) )
}
} )
router . POST ( "/api/tokenauth" , func ( c * gin . Context ) {
c . Request . ParseForm ( )
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 ( )
defer conn . Close ( )
var appidcheck , secretcheck , openid , logincode , pkce , pkcemethod string
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 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 10:45:58 +01:00
conn . Exec ( "DELETE FROM logins WHERE code = ?" , logincode )
2024-04-26 21:39:57 +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 { }
c . ShouldBindJSON ( & data )
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 ( )
defer conn . Close ( )
_ , err := conn . Exec ( "DELETE FROM oauth WHERE appId = ? AND creator = ?" , appId , id )
if err != nil {
if err == sql . ErrNoRows {
c . JSON ( 400 , gin . H { "error" : "AppID Not found" } )
} else {
fmt . Println ( "[ERROR] Unknown in /api/deleteauth at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
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 { }
c . ShouldBindJSON ( & data )
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 ( )
defer conn . Close ( )
for {
err := conn . QueryRow ( "SELECT secret FROM oauth WHERE secret = ?" , secret ) . Scan ( & testsecret )
if err != nil {
if err == sql . ErrNoRows {
break
} else {
fmt . Println ( "[ERROR] Unknown in /api/newauth secretselect at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
return
}
} else {
secret = genSalt ( 512 )
}
}
_ , err := conn . Exec ( "SELECT secret FROM oauth WHERE appId = ?" , appId )
if err != nil {
if err == sql . ErrNoRows {
fmt . Println ( "[Info] New Oauth source added with ID:" , appId )
} else {
fmt . Println ( "[ERROR] Unknown in /api/newauth at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
return
}
} else {
secret = genSalt ( 512 )
}
conn . Exec ( "INSERT INTO oauth (appId, creator, secret, rdiruri) VALUES (?, ?, ?, ?)" , appId , id , secret , rdiruri )
c . JSON ( 200 , gin . H { "key" : secret } )
} )
router . POST ( "/api/listauth" , func ( c * gin . Context ) {
var data map [ string ] interface { }
c . ShouldBindJSON ( & data )
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 ( )
defer conn . Close ( )
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
}
defer rows . Close ( )
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 { }
c . ShouldBindJSON ( & data )
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 ( )
defer conn . Close ( )
_ , err := conn . Exec ( "DELETE FROM userdata WHERE AND creator = ?" , id )
if err != nil {
if err != sql . ErrNoRows {
fmt . Println ( "[ERROR] Unknown in /api/deleteuser userdata at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
_ , err = conn . Exec ( "DELETE FROM logins WHERE creator = ?" , id )
if err != nil {
if err != sql . ErrNoRows {
fmt . Println ( "[ERROR] Unknown in /api/deleteuser logins at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
_ , err = conn . Exec ( "DELETE FROM oauth WHERE creator = ?" , id )
if err != nil {
if err != sql . ErrNoRows {
fmt . Println ( "[ERROR] Unknown in /api/deleteuser oauth at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
_ , err = conn . Exec ( "DELETE FROM users WHERE id = ?" , id )
if err != nil {
if err != sql . ErrNoRows {
fmt . Println ( "[ERROR] Unknown in /api/deleteuser logins at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
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 { }
c . ShouldBindJSON ( & data )
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 ( )
defer conn . Close ( )
rows , err := conn . Query ( "SELECT sessionid, session, device FROM sessions WHERE id = ? ORDER BY id DESC" , id )
if err != nil {
if err != sql . ErrNoRows {
fmt . Println ( "[ERROR] Unknown in /api/sessions/list at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
defer rows . Close ( )
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 { }
c . ShouldBindJSON ( & data )
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 ( )
defer conn . Close ( )
_ , err := conn . Exec ( "DELETE FROM sessions WHERE sessionid = ? AND id = ?" , sessionId , id )
if err != nil {
if err == sql . ErrNoRows {
c . JSON ( 422 , gin . H { "error" : "SessionID Not found" } )
} else {
fmt . Println ( "[ERROR] Unknown in /api/sessions/remove at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
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 { }
c . ShouldBindJSON ( & data )
masterkey := data [ "masterkey" ] . ( string )
if masterkey == SECRET_KEY {
conn := get_db_connection ( )
defer conn . Close ( )
rows , err := conn . Query ( "SELECT * FROM users ORDER BY id DESC" )
if err != nil {
if err != sql . ErrNoRows {
fmt . Println ( "[ERROR] Unknown in /api/listusers at" , strconv . FormatInt ( time . Now ( ) . Unix ( ) , 10 ) + ":" , err )
c . JSON ( 500 , gin . H { "error" : "Unknown error occured" } )
}
}
defer rows . Close ( )
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 )
}
} )
fmt . Println ( "[INFO] Server started at" , time . Now ( ) . Unix ( ) )
fmt . Println ( "[INFO] Welcome to Burgerauth! Today we are running on IP " + HOST + " on port " + strconv . Itoa ( PORT ) + "." )
router . Run ( HOST + ":" + strconv . Itoa ( PORT ) )
}