Fixed flaw with jellyfin_login; store refresh token in cookies

with jellyfin_login enabled, the username and password vals in the User
struct would be "". If you disabled 'required' on the login form, blank
username and password would allow you in.
pull/20/head v0.1.5
Harvey Tindall 4 years ago
parent d144077e62
commit ee3b421566
No known key found for this signature in database
GPG Key ID: BBC65952848FB1A2

@ -610,7 +610,15 @@ func (app *appContext) ModifyConfig(gc *gin.Context) {
}
func (app *appContext) Logout(gc *gin.Context) {
app.invalidIds = append(app.invalidIds, gc.GetString("userId"))
cookie, err := gc.Cookie("refresh")
if err != nil {
app.debug.Printf("Couldn't get cookies: %s", err)
respond(500, "Couldn't fetch cookies", gc)
return
}
app.invalidTokens = append(app.invalidTokens, cookie)
fmt.Println("After appending", cookie, ":", app.invalidTokens)
gc.SetCookie("refresh", "invalid", -1, "/", gc.Request.URL.Hostname(), true, true)
gc.JSON(200, map[string]bool{"success": true})
}

@ -87,18 +87,30 @@ func (app *appContext) GetToken(gc *gin.Context) {
var userId, jfId string
for _, user := range app.users {
if user.Username == creds[0] && user.Password == creds[1] {
if creds[0] != "" && creds[1] != "" {
match = true
app.debug.Println("Found existing user")
userId = user.UserID
}
}
}
if !match {
if !app.jellyfinLogin {
app.info.Println("Auth failed: Invalid username and/or password")
respond(401, "Unauthorized", gc)
return
}
if creds[1] == "" {
token, err := jwt.Parse(creds[0], func(token *jwt.Token) (interface{}, error) {
cookie, err := gc.Cookie("refresh")
if err == nil && cookie != "" && creds[0] == "" && creds[1] == "" {
fmt.Println("Checking:", cookie)
for _, token := range app.invalidTokens {
if cookie == token {
app.debug.Printf("Auth denied: Refresh token in blocklist")
respond(401, "Unauthorized", gc)
return
}
}
token, err := jwt.Parse(cookie, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
app.debug.Printf("Invalid JWT signing method %s", token.Header["alg"])
return nil, fmt.Errorf("Unexpected signing method %v", token.Header["alg"])
@ -111,13 +123,6 @@ func (app *appContext) GetToken(gc *gin.Context) {
return
}
claims, ok := token.Claims.(jwt.MapClaims)
for _, id := range app.invalidIds {
if claims["id"].(string) == id {
app.debug.Printf("Auth denied: Refresh token in blocklist")
respond(401, "Unauthorized", gc)
return
}
}
expiryUnix, err := strconv.ParseInt(claims["exp"].(string), 10, 64)
if err != nil {
app.debug.Printf("Auth denied: %s", err)
@ -168,7 +173,8 @@ func (app *appContext) GetToken(gc *gin.Context) {
if err != nil {
respond(500, "Error generating token", gc)
}
resp := map[string]string{"token": token, "refresh": refresh}
resp := map[string]string{"token": token}
gc.SetCookie("refresh", refresh, (3600 * 24), "/", gc.Request.URL.Hostname(), true, true)
gc.JSON(200, resp)
}

@ -531,7 +531,7 @@ document.getElementById('inviteForm').onsubmit = function() {
return false;
};
function tryLogin(username, password, modal, button) {
function tryLogin(username, password, modal, button, callback) {
let req = new XMLHttpRequest();
req.responseType = 'json';
req.onreadystatechange = function() {
@ -561,7 +561,6 @@ function tryLogin(username, password, modal, button) {
} else {
const data = this.response;
window.token = data['token'];
document.cookie = "refresh=" + data['refresh'];
generateInvites();
const interval = setInterval(function() { generateInvites(); }, 60 * 1000);
let day = document.getElementById('days');
@ -579,6 +578,9 @@ function tryLogin(username, password, modal, button) {
}
document.getElementById('logoutButton').setAttribute('style', '');
}
if (typeof callback === "function") {
callback(this.status);
}
}
};
req.open("GET", "/getToken", true);
@ -600,7 +602,7 @@ document.getElementById('loginForm').onsubmit = function() {
button.innerHTML =
'<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="margin-right: 0.5rem;"></span>' +
'Loading...';
tryLogin(details['username'], details['password'], true, button)
tryLogin(username = details['username'], password = details['password'], modal = true, button = button)
return false;
};
@ -807,12 +809,12 @@ document.getElementById('openUsers').onclick = function () {
generateInvites(empty = true);
let refreshToken = getCookie("refresh")
if (refreshToken != "") {
tryLogin(refreshToken, "", false)
} else {
tryLogin("", "", false, callback = function(code){
console.log(code);
if (code != 200) {
loginModal.show();
}
}
});
document.getElementById('logoutButton').onclick = function () {
let req = new XMLHttpRequest();
@ -822,7 +824,6 @@ document.getElementById('logoutButton').onclick = function () {
req.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
window.token = '';
document.cookie = 'refresh=;';
location.reload();
return false;
}

@ -42,7 +42,7 @@ type appContext struct {
bsVersion int
jellyfinLogin bool
users []User
invalidIds []string
invalidTokens []string
jf Jellyfin
authJf Jellyfin
datePattern string
@ -329,7 +329,7 @@ func main() {
router.Use(static.Serve("/invite/", static.LocalFile(filepath.Join(app.local_path, "static"), false)))
router.GET("/invite/:invCode", app.InviteProxy)
api := router.Group("/", app.webAuth())
api.POST("/logout", app.Logout)
router.POST("/logout", app.Logout)
api.POST("/generateInvite", app.GenerateInvite)
api.GET("/getInvites", app.GetInvites)
api.POST("/setNotify", app.SetNotify)

Loading…
Cancel
Save