Skip to content

Commit

Permalink
Merge branch 'master' into timeLimit#88
Browse files Browse the repository at this point in the history
  • Loading branch information
CptPie authored Feb 2, 2021
2 parents f28eb08 + 2457302 commit afbdc0e
Show file tree
Hide file tree
Showing 22 changed files with 2,578 additions and 143 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ SOURCES = \
admin.go \
api.go \
auth.go \
common/authmethod.go \
common/cycle.go \
common/logger.go \
common/movie.go \
Expand All @@ -23,6 +24,7 @@ SOURCES = \
templates.go \
user.go \
util.go \
oauth.go \
votes.go

.PHONY: all data fmt server
Expand Down
94 changes: 91 additions & 3 deletions admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,14 @@ func (s *Server) adminDeleteUser(w http.ResponseWriter, r *http.Request, user *c
s.l.Info("Deleting user %s", user)
origName := user.Name
user.Name = "[deleted]"
user.Password = ""
user.PassDate = time.Now()
for _, auth := range user.AuthMethods {
s.data.DeleteAuthMethod(auth.Id)
}
user.AuthMethods = []*common.AuthMethod{}
user.Email = ""
user.NotifyCycleEnd = false
user.NotifyVoteSelection = false
user.Privilege = 0
user.RateLimitOverride = false

err := s.data.UpdateUser(user)
if err != nil {
Expand Down Expand Up @@ -388,6 +389,20 @@ func (s *Server) handlerAdminConfig(w http.ResponseWriter, r *http.Request) {
configValue{Key: ConfigMaxMultEpLength, Default: DefaultMaxMultEpLength, Type: ConfigInt},

configValue{Key: ConfigUnlimitedVotes, Default: DefaultUnlimitedVotes, Type: ConfigBool},

configValue{Key: ConfigLocalSignupEnabled, Default: DefaultLocalSignupEnabled, Type: ConfigBool},
configValue{Key: ConfigTwitchOauthEnabled, Default: DefaultTwitchOauthEnabled, Type: ConfigBool},
configValue{Key: ConfigTwitchOauthSignupEnabled, Default: DefaultTwitchOauthSignupEnabled, Type: ConfigBool},
configValue{Key: ConfigTwitchOauthClientID, Default: DefaultTwitchOauthClientID, Type: ConfigString},
configValue{Key: ConfigTwitchOauthClientSecret, Default: DefaultTwitchOauthClientSecret, Type: ConfigString},
configValue{Key: ConfigDiscordOauthEnabled, Default: DefaultDiscordOauthEnabled, Type: ConfigBool},
configValue{Key: ConfigDiscordOauthSignupEnabled, Default: DefaultDiscordOauthSignupEnabled, Type: ConfigBool},
configValue{Key: ConfigDiscordOauthClientID, Default: DefaultDiscordOauthClientID, Type: ConfigString},
configValue{Key: ConfigDiscordOauthClientSecret, Default: DefaultDiscordOauthClientSecret, Type: ConfigString},
configValue{Key: ConfigPatreonOauthEnabled, Default: DefaultPatreonOauthEnabled, Type: ConfigBool},
configValue{Key: ConfigPatreonOauthSignupEnabled, Default: DefaultPatreonOauthSignupEnabled, Type: ConfigBool},
configValue{Key: ConfigPatreonOauthClientID, Default: DefaultPatreonOauthClientID, Type: ConfigString},
configValue{Key: ConfigPatreonOauthClientSecret, Default: DefaultPatreonOauthClientSecret, Type: ConfigString},
},

TypeString: ConfigString,
Expand Down Expand Up @@ -492,6 +507,79 @@ func (s *Server) handlerAdminConfig(w http.ResponseWriter, r *http.Request) {
// Set this down here so the Notice Banner is updated
data.dataPageBase = s.newPageBase("Admin - Config", w, r)

// Reload Oauth
err = s.initOauth()

if err != nil {
data.ErrorMessage = append(data.ErrorMessage, err.Error())
}

// getting ALL the booleans
var localSignup, twitchSignup, patreonSignup, discordSignup, twitchOauth, patreonOauth, discordOauth bool

for _, val := range data.Values {
bval, ok := val.Value.(bool)
if !ok && val.Type == ConfigBool {
data.ErrorMessage = append(data.ErrorMessage, "Could not parse field %s as boolean", val.Key)
break
}
switch val.Key {
case ConfigLocalSignupEnabled:
localSignup = bval
case ConfigTwitchOauthSignupEnabled:
twitchSignup = bval
case ConfigTwitchOauthEnabled:
twitchOauth = bval
case ConfigDiscordOauthSignupEnabled:
discordSignup = bval
case ConfigDiscordOauthEnabled:
discordOauth = bval
case ConfigPatreonOauthSignupEnabled:
patreonSignup = bval
case ConfigPatreonOauthEnabled:
patreonOauth = bval
}
}

// Check that we have atleast ONE signup method enabled
if !(localSignup || twitchSignup || discordSignup || patreonSignup) {
data.ErrorMessage = append(data.ErrorMessage, "No Signup method is currently enabled, please ensure to enable atleast one method")
}

// Check that the corresponding oauth for the signup is enabled
if twitchSignup && !twitchOauth {
data.ErrorMessage = append(data.ErrorMessage, "To enable twitch signup you need to also enable twitch Oauth (and fill the token/secret)")
}

if discordSignup && !discordOauth {
data.ErrorMessage = append(data.ErrorMessage, "To enable discord signup you need to also enable discord Oauth (and fill the token/secret)")
}

if patreonSignup && !patreonOauth {
data.ErrorMessage = append(data.ErrorMessage, "To enable patreon signup you need to also enable patreon Oauth (and fill the token/secret)")
}

users, err := s.data.GetUsersWithAuth(common.AUTH_TWITCH, true)
if err, ok := err.(*common.ErrNoUsersFound); !ok || err == nil {
if (len(users) != 0) && !twitchOauth {
data.ErrorMessage = append(data.ErrorMessage, fmt.Sprintf("Disabling Twitch Oauth would cause %d users to be unable to login since they only have this auth method associated.", len(users)))
}
}

users, err = s.data.GetUsersWithAuth(common.AUTH_PATREON, true)
if err, ok := err.(*common.ErrNoUsersFound); !ok || err == nil {
if (len(users) != 0) && !patreonOauth {
data.ErrorMessage = append(data.ErrorMessage, fmt.Sprintf("Disabling Patreon Oauth would cause %d users to be unable to login since they only have this auth method associated.", len(users)))
}
}

users, err = s.data.GetUsersWithAuth(common.AUTH_DISCORD, true)
if err, ok := err.(*common.ErrNoUsersFound); !ok || err == nil {
if (len(users) != 0) && !discordOauth {
data.ErrorMessage = append(data.ErrorMessage, fmt.Sprintf("Disabling Discord Oauth would cause %d users to be unable to login since they only have this auth method associated.", len(users)))
}
}

if err := s.executeTemplate(w, "adminConfig", data); err != nil {
s.l.Error("Error rendering template: %v", err)
}
Expand Down
19 changes: 13 additions & 6 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"net/http"
"regexp"
//"strconv"
"strings"
"time"

Expand Down Expand Up @@ -120,16 +119,24 @@ func (s *Server) handlerAuth(w http.ResponseWriter, r *http.Request) {
return
}

user.Password = s.hashPassword(pass1)
user.PassDate = time.Now()
var localAuth *common.AuthMethod
for _, auth := range user.AuthMethods {
if auth.Type == common.AUTH_LOCAL {
localAuth = auth
break
}
}

localAuth.Password = s.hashPassword(pass1)
localAuth.Date = time.Now()

if err = s.data.UpdateUser(user); err != nil {
s.l.Error("Unable to save User with new password:", err)
if err = s.data.UpdateAuthMethod(localAuth); err != nil {
s.l.Error("Unable to save AuthMethod with new password:", err)
s.doError(http.StatusInternalServerError, "Unable to update password", w, r)
return
}

if err = s.login(user, w, r); err != nil {
if err = s.login(user, common.AUTH_LOCAL, w, r); err != nil {
s.l.Error("Unable to login to session:", err)
s.doError(http.StatusInternalServerError, "Something went wrong :C", w, r)
return
Expand Down
131 changes: 131 additions & 0 deletions cmd/migrateUsers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"time"

"github.com/mitchellh/mapstructure"
mpc "github.com/zorchenhimer/MoviePolls/common"
mpd "github.com/zorchenhimer/MoviePolls/data"
)

const jsonFilename string = "db/data.json"

func main() {
err := loadOldDB()
if err != nil {
fmt.Printf("%v\n", err)
}
}

type OldUser struct {
Id int
Name string
Password string
OAuthToken string
Email string
NotifyCycleEnd bool
NotifyVoteSelection bool
Privilege int
PassDate time.Time
RateLimitOverride bool
LastMovieAdd time.Time
}

func loadOldDB() error {

data, err := ioutil.ReadFile(jsonFilename)
if err != nil {
fmt.Println(err)
}

var fullData map[string]interface{}

json.Unmarshal(data, &fullData)

// fullData now contains the whole db
jUsers := fullData["Users"].(map[string]interface{})
oldUsers := []OldUser{}
for _, user := range jUsers {
ou := &OldUser{}
mapstructure.Decode(user, &ou)
// lets parse the fucking time by hand
if user.(map[string]interface{})["PassDate"] == nil {
fmt.Println("[ERROR] Could not parse field 'PassDate', was the database already converted?")
return nil
}
ou.PassDate, err = time.Parse(time.RFC3339, user.(map[string]interface{})["PassDate"].(string))
if err != nil {
fmt.Println("[ERROR] Could not parse field 'PassDate', was the database already converted?")
return nil
}
oldUsers = append(oldUsers, *ou)
}

delete(fullData, "Users")

data, err = json.MarshalIndent(fullData, "", " ")

// write a temporary file which contains the db without the "users"
err = ioutil.WriteFile("db/temp.json", data, 0666)
if err != nil {
return err
}

l, err := mpc.NewLogger(mpc.LLDebug, "")

if err != nil {
return err
}

dc, err := mpd.GetDataConnector("json", "db/temp.json", l)

if err != nil {
return err
}

for _, oldUser := range oldUsers {

// convert old movies to new ones
newUser := mpc.User{
Id: oldUser.Id,
Name: oldUser.Name,
Email: oldUser.Email,
NotifyCycleEnd: oldUser.NotifyCycleEnd,
NotifyVoteSelection: oldUser.NotifyVoteSelection,
Privilege: mpc.PrivilegeLevel(oldUser.Privilege),
}

// Do NOT build new entries for users with empty passwords (i.e. Deleted users)
if oldUser.Password != "" {
authMethod := &mpc.AuthMethod{
Type: mpc.AUTH_LOCAL,
Password: oldUser.Password,
Date: oldUser.PassDate,
}

newUser.AuthMethods = []*mpc.AuthMethod{}

id, err := dc.AddAuthMethod(authMethod)

if err != nil {
return err
}

authMethod.Id = id

newUser.AuthMethods = append(newUser.AuthMethods, authMethod)
}
dc.UpdateUser(&newUser)
}

err = os.Rename("db/temp.json", jsonFilename)
if err != nil {
return err
}

return nil
}
22 changes: 22 additions & 0 deletions common/authmethod.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package common

import "time"

type AuthType string

const (
AUTH_DISCORD = "Discord"
AUTH_TWITCH = "Twitch"
AUTH_PATREON = "Patreon"
AUTH_LOCAL = "Local"
)

type AuthMethod struct {
Id int
ExtId string
Type AuthType
Password string
AuthToken string
RefreshToken string
Date time.Time
}
13 changes: 13 additions & 0 deletions common/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package common

import (
"fmt"
)

type ErrNoUsersFound struct {
Auth AuthType
}

func (e *ErrNoUsersFound) Error() string {
return fmt.Sprintf("No users found with AuthType %v", e.Auth)
}
14 changes: 11 additions & 3 deletions common/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ var re_validLink = *regexp.MustCompile(`[a-zA-Z0-9:._\+]{1,256}\.[a-zA-Z0-9()]{1

func (l *Link) validateLink() error {
url := l.Url
url = cleanupLink(url)
if re_validLink.MatchString(url) {
url = stripRefFromLink(url)

if len(url) <= 8 {
// lets be stupid when the link is too short
Expand All @@ -68,11 +68,19 @@ func (l *Link) validateLink() error {
return fmt.Errorf("Invalid link: %v", l.Url)
}

func stripRefFromLink(link string) string {
var replacements = map[string]string{
"m.imdb.com": "imdb.com",
}

func cleanupLink(link string) string {
idx := strings.Index(link, "/?")
if idx != -1 {
return link[:idx]
link = link[:idx]
}
for from, to := range replacements {
link = strings.Replace(link, from, to, 1)
}

return link
}

Expand Down
Loading

0 comments on commit afbdc0e

Please sign in to comment.