@ -3,8 +3,9 @@ package main
import (
import (
"fmt"
"fmt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/knz/strtime"
"github.com/knz/strtime"
"github.com/lithammer/shortuuid/v3"
"gopkg.in/ini.v1"
"time"
"time"
)
)
@ -82,25 +83,24 @@ func (ctx *appContext) checkInvite(code string, used bool, username string) bool
changed := false
changed := false
for invCode , data := range ctx . storage . invites {
for invCode , data := range ctx . storage . invites {
expiry := data . ValidTill
expiry := data . ValidTill
fmt . Println ( "Expiry:" , expiry )
if current_time . After ( expiry ) {
if current_time . After ( expiry ) {
// NOTIFICATIONS
ctx . debug . Printf ( "Housekeeping: Deleting old invite %s" , code )
notify := data . Notify
notify := data . Notify
if ctx . config . Section ( "notifications" ) . Key ( "enabled" ) . MustBool ( false ) && len ( notify ) != 0 {
if ctx . config . Section ( "notifications" ) . Key ( "enabled" ) . MustBool ( false ) && len ( notify ) != 0 {
ctx . debug . Printf ( "%s: Expiry notification" , code )
for address , settings := range notify {
for address , settings := range notify {
if settings [ "notify-expiry" ] {
if settings [ "notify-expiry" ] {
if ctx . email . constructExpiry ( invCode , data , ctx ) != nil {
if ctx . email . constructExpiry ( invCode , data , ctx ) != nil {
fmt . Println ( "failed expiry construct" )
ctx . err . Printf ( "%s: Failed to construct expiry notification" , code )
} else if ctx . email . send ( address , ctx ) != nil {
ctx . err . Printf ( "%s: Failed to send expiry notification" , code )
} else {
} else {
if ctx . email . send ( address , ctx ) != nil {
ctx . info . Printf ( "Sent expiry notification to %s" , address )
fmt . Println ( "failed expiry send" )
}
}
}
}
}
}
}
}
}
changed = true
changed = true
fmt . Println ( "Deleting:" , invCode )
delete ( ctx . storage . invites , invCode )
delete ( ctx . storage . invites , invCode )
} else if invCode == code {
} else if invCode == code {
match = true
match = true
@ -130,7 +130,6 @@ func (ctx *appContext) checkInvite(code string, used bool, username string) bool
// Routes from now on!
// Routes from now on!
// POST
type newUserReq struct {
type newUserReq struct {
Username string ` json:"username" `
Username string ` json:"username" `
Password string ` json:"password" `
Password string ` json:"password" `
@ -141,7 +140,9 @@ type newUserReq struct {
func ( ctx * appContext ) NewUser ( gc * gin . Context ) {
func ( ctx * appContext ) NewUser ( gc * gin . Context ) {
var req newUserReq
var req newUserReq
gc . BindJSON ( & req )
gc . BindJSON ( & req )
ctx . debug . Printf ( "%s: New user attempt" , req . Code )
if ! ctx . checkInvite ( req . Code , false , "" ) {
if ! ctx . checkInvite ( req . Code , false , "" ) {
ctx . info . Printf ( "%s New user failed: invalid code" , req . Code )
gc . JSON ( 401 , map [ string ] bool { "success" : false } )
gc . JSON ( 401 , map [ string ] bool { "success" : false } )
gc . Abort ( )
gc . Abort ( )
return
return
@ -155,18 +156,21 @@ func (ctx *appContext) NewUser(gc *gin.Context) {
}
}
if ! valid {
if ! valid {
// 200 bcs idk what i did in js
// 200 bcs idk what i did in js
fmt. Println ( "invalid" )
ctx. info . Printf ( "%s New user failed: Invalid password" , req . Code )
gc . JSON ( 200 , validation )
gc . JSON ( 200 , validation )
gc . Abort ( )
gc . Abort ( )
return
return
}
}
existingUser , _ , _ := ctx . jf . userByName ( req . Username , false )
existingUser , _ , _ := ctx . jf . userByName ( req . Username , false )
if existingUser != nil {
if existingUser != nil {
respond ( 401 , fmt . Sprintf ( "User already exists named %s" , req . Username ) , gc )
msg := fmt . Sprintf ( "User already exists named %s" , req . Username )
ctx . info . Printf ( "%s New user failed: %s" , req . Code , msg )
respond ( 401 , msg , gc )
return
return
}
}
user , status , err := ctx . jf . newUser ( req . Username , req . Password )
user , status , err := ctx . jf . newUser ( req . Username , req . Password )
if ! ( status == 200 || status == 204 ) || err != nil {
if ! ( status == 200 || status == 204 ) || err != nil {
ctx . err . Printf ( "%s New user failed: Jellyfin responded with %d" , req . Code , status )
respond ( 401 , "Unknown error" , gc )
respond ( 401 , "Unknown error" , gc )
return
return
}
}
@ -176,9 +180,13 @@ func (ctx *appContext) NewUser(gc *gin.Context) {
for address , settings := range invite . Notify {
for address , settings := range invite . Notify {
if settings [ "notify-creation" ] {
if settings [ "notify-creation" ] {
if ctx . email . constructCreated ( req . Code , req . Username , req . Email , invite , ctx ) != nil {
if ctx . email . constructCreated ( req . Code , req . Username , req . Email , invite , ctx ) != nil {
fmt . Println ( "created template failed" )
ctx . err . Printf ( "%s: Failed to construct user creation notification" , req . Code )
ctx . debug . Printf ( "%s: Error: %s" , req . Code , err )
} else if ctx . email . send ( address , ctx ) != nil {
} else if ctx . email . send ( address , ctx ) != nil {
fmt . Println ( "created send failed" )
ctx . err . Printf ( "%s: Failed to send user creation notification" , req . Code )
ctx . debug . Printf ( "%s: Error: %s" , req . Code , err )
} else {
ctx . info . Printf ( "%s: Sent user creation notification to %s" , req . Code , address )
}
}
}
}
}
}
@ -190,13 +198,15 @@ func (ctx *appContext) NewUser(gc *gin.Context) {
if len ( ctx . storage . policy ) != 0 {
if len ( ctx . storage . policy ) != 0 {
status , err = ctx . jf . setPolicy ( id , ctx . storage . policy )
status , err = ctx . jf . setPolicy ( id , ctx . storage . policy )
if ! ( status == 200 || status == 204 ) {
if ! ( status == 200 || status == 204 ) {
fmt. Printf ( "Failed to set user policy" )
ctx. err . Printf ( "%s: Failed to set user policy: Code %d" , req . Code , status )
}
}
}
}
if len ( ctx . storage . configuration ) != 0 && len ( ctx . storage . displayprefs ) != 0 {
if len ( ctx . storage . configuration ) != 0 && len ( ctx . storage . displayprefs ) != 0 {
status , err = ctx . jf . setConfiguration ( id , ctx . storage . configuration )
status , err = ctx . jf . setConfiguration ( id , ctx . storage . configuration )
if ( status == 200 || status == 204 ) && err ! = nil {
if ( status == 200 || status == 204 ) && err = = nil {
status , err = ctx . jf . setDisplayPreferences ( id , ctx . storage . displayprefs )
status , err = ctx . jf . setDisplayPreferences ( id , ctx . storage . displayprefs )
} else {
ctx . err . Printf ( "%s: Failed to set configuration template: Code %d" , req . Code , status )
}
}
}
}
if ctx . config . Section ( "password_resets" ) . Key ( "enabled" ) . MustBool ( false ) {
if ctx . config . Section ( "password_resets" ) . Key ( "enabled" ) . MustBool ( false ) {
@ -213,18 +223,18 @@ type generateInviteReq struct {
Email string ` json:"email" `
Email string ` json:"email" `
MultipleUses bool ` json:"multiple-uses" `
MultipleUses bool ` json:"multiple-uses" `
NoLimit bool ` json:"no-limit" `
NoLimit bool ` json:"no-limit" `
RemainingUses int ` json: remaining-uses"`
RemainingUses int ` json: " remaining-uses"`
}
}
func ( ctx * appContext ) GenerateInvite ( gc * gin . Context ) {
func ( ctx * appContext ) GenerateInvite ( gc * gin . Context ) {
var req generateInviteReq
var req generateInviteReq
ctx . debug . Println ( "Generating new invite" )
ctx . storage . loadInvites ( )
ctx . storage . loadInvites ( )
gc . BindJSON ( & req )
gc . BindJSON ( & req )
current_time := time . Now ( )
current_time := time . Now ( )
fmt . Println ( req . Days , req . Hours , req . Minutes )
valid_till := current_time . AddDate ( 0 , 0 , req . Days )
valid_till := current_time . AddDate ( 0 , 0 , req . Days )
valid_till = valid_till . Add ( time . Hour * time . Duration ( req . Hours ) + time . Minute * time . Duration ( req . Minutes ) )
valid_till = valid_till . Add ( time . Hour * time . Duration ( req . Hours ) + time . Minute * time . Duration ( req . Minutes ) )
invite_code , _ := uuid. New Random ( )
invite_code := short uuid. New ( )
var invite Invite
var invite Invite
invite . Created = current_time
invite . Created = current_time
if req . MultipleUses {
if req . MultipleUses {
@ -238,22 +248,27 @@ func (ctx *appContext) GenerateInvite(gc *gin.Context) {
}
}
invite . ValidTill = valid_till
invite . ValidTill = valid_till
if req . Email != "" && ctx . config . Section ( "invite_emails" ) . Key ( "enabled" ) . MustBool ( false ) {
if req . Email != "" && ctx . config . Section ( "invite_emails" ) . Key ( "enabled" ) . MustBool ( false ) {
ctx . debug . Printf ( "%s: Sending invite email" , invite_code )
invite . Email = req . Email
invite . Email = req . Email
if err := ctx . email . constructInvite ( invite_code . String ( ) , invite , ctx ) ; err != nil {
if err := ctx . email . constructInvite ( invite_code , invite , ctx ) ; err != nil {
fmt . Println ( "error sending:" , err )
invite . Email = fmt . Sprintf ( "Failed to send to %s" , req . Email )
invite . Email = fmt . Sprintf ( "Failed to send to %s" , req . Email )
ctx . err . Printf ( "%s: Failed to construct invite email" , invite_code )
ctx . debug . Printf ( "%s: Error: %s" , invite_code , err )
} else if err := ctx . email . send ( req . Email , ctx ) ; err != nil {
} else if err := ctx . email . send ( req . Email , ctx ) ; err != nil {
fmt . Println ( "error sending:" , err )
invite . Email = fmt . Sprintf ( "Failed to send to %s" , req . Email )
invite . Email = fmt . Sprintf ( "Failed to send to %s" , req . Email )
ctx . err . Printf ( "%s: %s" , invite_code , invite . Email )
ctx . debug . Printf ( "%s: Error: %s" , invite_code , err )
} else {
ctx . info . Printf ( "%s: Sent invite email to %s" , invite_code , req . Email )
}
}
}
}
ctx . storage . invites [ invite_code . String ( ) ] = invite
ctx . storage . invites [ invite_code ] = invite
fmt . Println ( "INVITES FROM API:" , ctx . storage . invites )
ctx . storage . storeInvites ( )
ctx . storage . storeInvites ( )
fmt . Println ( "New inv" )
gc . JSON ( 200 , map [ string ] bool { "success" : true } )
gc . JSON ( 200 , map [ string ] bool { "success" : true } )
}
}
// logged up to here!
func ( ctx * appContext ) GetInvites ( gc * gin . Context ) {
func ( ctx * appContext ) GetInvites ( gc * gin . Context ) {
current_time := time . Now ( )
current_time := time . Now ( )
// checking one checks all of them
// checking one checks all of them
@ -494,3 +509,20 @@ func (ctx *appContext) GetConfig(gc *gin.Context) {
}
}
gc . JSON ( 200 , resp )
gc . JSON ( 200 , resp )
}
}
func ( ctx * appContext ) ModifyConfig ( gc * gin . Context ) {
var req map [ string ] interface { }
gc . BindJSON ( & req )
tempConfig , _ := ini . Load ( ctx . config_path )
for section , settings := range req {
_ , err := tempConfig . GetSection ( section )
if section != "restart-program" && err == nil {
for setting , value := range settings . ( map [ string ] interface { } ) {
tempConfig . Section ( section ) . Key ( setting ) . SetValue ( value . ( string ) )
}
}
}
tempConfig . SaveTo ( ctx . config_path )
gc . JSON ( 200 , map [ string ] bool { "success" : true } )
ctx . loadConfig ( )
}