2022-09-03 14:16:41 +00:00
package main
import (
"bytes"
"fmt"
"log"
"net/http"
"net/mail"
"strconv"
"time"
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/gin-gonic/gin"
)
2022-09-10 10:14:11 +00:00
func declareAPIKeysRoutes ( router * gin . RouterGroup ) {
usersRoutes := router . Group ( "/users/:uid" )
usersRoutes . Use ( userHandler )
usersRoutes . GET ( "/pgp_keys" , func ( c * gin . Context ) {
var u * User
if user , ok := c . Get ( "user" ) ; ok {
u = user . ( * User )
} else {
u = c . MustGet ( "LoggedUser" ) . ( * User )
}
keys , err := u . GetKeys ( )
if err != nil {
log . Println ( "Unable to GetKeys:" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : "Unable to retrieve your keys. Please try again in a few moment." } )
return
}
var ret [ ] byte
2022-09-13 22:19:43 +00:00
if len ( keys ) == 0 {
ret , err = GitLab_getUserPGPKeys ( c . Request . Context ( ) , u )
if err != nil {
log . Println ( "Unable to GitLab_getUserPGPKeys:" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : "Unable to retrieve your keys from GitLab. Please try again in a few moment or add them directly on /keys page on this website." } )
return
}
} else {
for _ , key := range keys {
if key . Type == "pgp" {
ret = append ( ret , [ ] byte ( key . Content ) ... )
}
2022-09-10 10:14:11 +00:00
}
}
c . Data ( http . StatusOK , "application/pgp-keys" , ret )
} )
}
2022-09-03 14:16:41 +00:00
func declareAPIAuthKeysRoutes ( router * gin . RouterGroup ) {
router . GET ( "/keys" , func ( c * gin . Context ) {
var u * User
if user , ok := c . Get ( "user" ) ; ok {
u = user . ( * User )
} else {
u = c . MustGet ( "LoggedUser" ) . ( * User )
}
keys , err := u . GetKeys ( )
if err != nil {
log . Println ( "Unable to GetKeys:" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : "Unable to retrieve your keys. Please try again in a few moment." } )
return
}
var ret [ ] int64
for _ , key := range keys {
ret = append ( ret , key . Id )
}
c . JSON ( http . StatusOK , ret )
} )
router . POST ( "/keys" , func ( c * gin . Context ) {
var u * User
if user , ok := c . Get ( "user" ) ; ok {
u = user . ( * User )
} else {
u = c . MustGet ( "LoggedUser" ) . ( * User )
}
var key Key
if err := c . ShouldBindJSON ( & key ) ; err != nil {
c . AbortWithStatusJSON ( http . StatusBadRequest , gin . H { "errmsg" : err . Error ( ) } )
return
}
2022-09-04 15:59:51 +00:00
if err := key . CheckKey ( ) ; err != nil {
c . AbortWithStatusJSON ( http . StatusBadRequest , gin . H { "errmsg" : err . Error ( ) } )
return
}
2022-09-19 22:35:01 +00:00
k2 := key
if err := k2 . ReadInfos ( u ) ; err != nil {
c . AbortWithStatusJSON ( http . StatusBadRequest , gin . H { "errmsg" : err . Error ( ) } )
return
}
2022-09-03 14:16:41 +00:00
k , err := u . NewKey ( key . Type , key . Content )
if err != nil {
log . Println ( "Unable to NewKey:" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : "Unable to register your public key. Please try again in a few moment." } )
return
}
c . JSON ( http . StatusOK , k )
} )
keysRoutes := router . Group ( "/keys/:kid" )
keysRoutes . Use ( keyHandler )
2022-09-09 22:37:29 +00:00
keysRoutes . Use ( keyOnlyMyHandler )
2022-09-03 14:16:41 +00:00
keysRoutes . GET ( "" , func ( c * gin . Context ) {
var u * User
if user , ok := c . Get ( "user" ) ; ok {
u = user . ( * User )
} else {
u = c . MustGet ( "LoggedUser" ) . ( * User )
}
k := c . MustGet ( "key" ) . ( * Key )
if err := k . ReadInfos ( u ) ; err != nil {
2022-09-19 22:52:25 +00:00
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : fmt . Sprintf ( "Unable to read your public key: %s" , err . Error ( ) ) } )
2022-09-03 14:16:41 +00:00
return
}
c . JSON ( http . StatusOK , k )
} )
2022-09-09 22:37:48 +00:00
keysRoutes . GET ( "export" , func ( c * gin . Context ) {
c . JSON ( http . StatusOK , c . MustGet ( "key" ) . ( * Key ) )
} )
2022-09-03 14:16:41 +00:00
keysRoutes . PUT ( "" , func ( c * gin . Context ) {
current := c . MustGet ( "key" ) . ( * Key )
var new Key
if err := c . ShouldBindJSON ( & new ) ; err != nil {
c . AbortWithStatusJSON ( http . StatusBadRequest , gin . H { "errmsg" : err . Error ( ) } )
return
}
new . Id = current . Id
u := c . MustGet ( "LoggedUser" ) . ( * User )
if new . IdUser != current . IdUser && ! u . IsAdmin {
c . AbortWithStatusJSON ( http . StatusForbidden , gin . H { "errmsg" : "Operation not allowed." } )
return
}
if key , err := new . Update ( ) ; err != nil {
log . Println ( "Unable to Update key:" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : fmt . Sprintf ( "An error occurs during key updation: %s" , err . Error ( ) ) } )
return
} else {
c . JSON ( http . StatusOK , key )
}
} )
keysRoutes . DELETE ( "" , func ( c * gin . Context ) {
key := c . MustGet ( "key" ) . ( * Key )
if _ , err := key . Delete ( ) ; err != nil {
log . Println ( "Unable to Delete key:" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : fmt . Sprintf ( "An error occurs during key deletion: %s" , err . Error ( ) ) } )
return
} else {
c . JSON ( http . StatusOK , nil )
}
} )
}
func keyHandler ( c * gin . Context ) {
var u * User
if user , ok := c . Get ( "user" ) ; ok {
u = user . ( * User )
} else {
u = c . MustGet ( "LoggedUser" ) . ( * User )
}
if kid , err := strconv . Atoi ( string ( c . Param ( "kid" ) ) ) ; err != nil {
c . AbortWithStatusJSON ( http . StatusBadRequest , gin . H { "errmsg" : "Bad key identifier." } )
return
2022-09-16 09:37:55 +00:00
} else if c . MustGet ( "LoggedUser" ) . ( * User ) . IsAdmin {
2022-09-03 14:16:41 +00:00
if key , err := getKey ( kid ) ; err != nil {
c . AbortWithStatusJSON ( http . StatusNotFound , gin . H { "errmsg" : "Key not found." } )
return
} else {
c . Set ( "key" , key )
c . Next ( )
}
} else if key , err := u . getKey ( kid ) ; err != nil {
c . AbortWithStatusJSON ( http . StatusNotFound , gin . H { "errmsg" : "Key not found." } )
return
} else {
c . Set ( "key" , key )
c . Next ( )
}
}
2022-09-09 22:37:29 +00:00
func keyOnlyMyHandler ( c * gin . Context ) {
u := c . MustGet ( "LoggedUser" ) . ( * User )
k := c . MustGet ( "key" ) . ( * Key )
if u . IsAdmin {
c . Next ( )
} else if k . IdUser == u . Id {
c . Next ( )
} else {
c . AbortWithStatusJSON ( http . StatusNotFound , gin . H { "errmsg" : "Key not found." } )
return
}
}
2022-09-03 14:16:41 +00:00
type Key struct {
Id int64 ` json:"id" `
IdUser int64 ` json:"id_user" `
Type string ` json:"type" `
Content string ` json:"key,omitempty" `
Time time . Time ` json:"time" `
Infos map [ string ] interface { } ` json:"infos,omitempty" `
}
func ( u * User ) GetKeys ( ) ( keys [ ] * Key , err error ) {
if rows , errr := DBQuery ( "SELECT id_key, id_user, type, content, time FROM user_keys WHERE id_user=?" , u . Id ) ; errr != nil {
return nil , errr
} else {
defer rows . Close ( )
for rows . Next ( ) {
var k Key
if err = rows . Scan ( & k . Id , & k . IdUser , & k . Type , & k . Content , & k . Time ) ; err != nil {
return
}
keys = append ( keys , & k )
}
if err = rows . Err ( ) ; err != nil {
return
}
return
}
}
func getKey ( id int ) ( k * Key , err error ) {
k = new ( Key )
err = DBQueryRow ( "SELECT id_key, id_user, type, content, time FROM user_keys WHERE id_key=?" , id ) . Scan ( & k . Id , & k . IdUser , & k . Type , & k . Content , & k . Time )
return
}
func ( u * User ) getKey ( id int ) ( k * Key , err error ) {
k = new ( Key )
err = DBQueryRow ( "SELECT id_key, id_user, type, content, time FROM user_keys WHERE id_key=? AND id_user=?" , id , u . Id ) . Scan ( & k . Id , & k . IdUser , & k . Type , & k . Content , & k . Time )
return
}
func ( u * User ) NewKey ( kind , content string ) ( * Key , error ) {
if res , err := DBExec ( "INSERT INTO user_keys (id_user, type, content) VALUES (?, ?, ?)" , u . Id , kind , content ) ; err != nil {
return nil , err
} else if kid , err := res . LastInsertId ( ) ; err != nil {
return nil , err
} else {
return & Key { kid , u . Id , kind , content , time . Now ( ) , nil } , nil
}
}
func ( k * Key ) CheckKey ( ) error {
if k . Type == "pgp" {
keys , err := openpgp . ReadArmoredKeyRing ( bytes . NewBufferString ( k . Content ) )
if err != nil {
return err
}
if len ( keys ) != 1 {
return fmt . Errorf ( "This is not a single public key file." )
}
if keys [ 0 ] . PrivateKey != nil {
return fmt . Errorf ( "You send your PRIVATE key along with your public key. YOUR PRIVATE KEY IS COMPROMISED. Please revoke and regenerate a new key pair." )
}
if keys [ 0 ] . Revocations != nil {
return fmt . Errorf ( "Your key seems to be revoked." )
}
return nil
} else {
return fmt . Errorf ( "%q is not a valid key type." , k . Type )
}
}
func ( k * Key ) ReadInfos ( u * User ) error {
if k . Type == "pgp" {
keys , err := openpgp . ReadArmoredKeyRing ( bytes . NewBufferString ( k . Content ) )
if err != nil {
return err
}
k . Content = ""
k . Infos = map [ string ] interface { } { }
var std_identity * openpgp . Identity
for name , idt := range keys [ 0 ] . Identities {
if idt . Revoked ( time . Now ( ) ) {
continue
}
address , err := mail . ParseAddress ( name )
if err != nil {
continue
}
if address . Address == u . Email {
std_identity = idt
break
}
}
2022-09-08 15:59:52 +00:00
if std_identity == nil {
return fmt . Errorf ( "No identity found with %s email address." , u . Email )
}
2022-09-03 14:16:41 +00:00
if std_identity . UserId != nil {
k . Infos [ "identity" ] = std_identity . UserId . Name
k . Infos [ "email" ] = std_identity . UserId . Email
k . Infos [ "comment" ] = std_identity . UserId . Comment
}
if std_identity . SelfSignature != nil {
k . Infos [ "keyid" ] = fmt . Sprintf ( "%X" , std_identity . SelfSignature . IssuerFingerprint )
k . Infos [ "sigexpired" ] = std_identity . SelfSignature . SigExpired ( time . Now ( ) )
k . Infos [ "creation" ] = std_identity . SelfSignature . CreationTime
}
return nil
} else {
return fmt . Errorf ( "%q is not a valid key type." , k . Type )
}
}
func ( k * Key ) Update ( ) ( * Key , error ) {
if _ , err := DBExec ( "UPDATE user_keys SET id_user = ?, type = ?, content = ? WHERE id_key = ?" , k . IdUser , k . Type , k . Content , k . Content , k . Id ) ; err != nil {
return nil , err
} else {
return k , err
}
}
func ( k Key ) Delete ( ) ( int64 , error ) {
if res , err := DBExec ( "DELETE FROM user_keys WHERE id_key = ?" , k . Id ) ; err != nil {
return 0 , err
} else if nb , err := res . RowsAffected ( ) ; err != nil {
return 0 , err
} else {
return nb , err
}
}
func ClearKeys ( ) ( int64 , error ) {
if res , err := DBExec ( "DELETE FROM user_keys" ) ; err != nil {
return 0 , err
} else if nb , err := res . RowsAffected ( ) ; err != nil {
return 0 , err
} else {
return nb , err
}
}