Improve HTTP header auth
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
0becb8a92d
commit
f88c574f3f
13 changed files with 98 additions and 32 deletions
|
@ -8,19 +8,18 @@ export default class Session {
|
|||
constructor(storage) {
|
||||
this.auth = false;
|
||||
|
||||
if(storage.getItem("session_storage") === "true") {
|
||||
if (storage.getItem("session_storage") === "true") {
|
||||
this.storage = window.sessionStorage;
|
||||
} else {
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
this.session_token = this.storage.getItem("session_token");
|
||||
if (this.applyToken(this.storage.getItem("session_token"))) {
|
||||
const userJson = this.storage.getItem("user");
|
||||
this.user = userJson !== "undefined" ? new User(JSON.parse(userJson)) : null;
|
||||
}
|
||||
|
||||
const userJson = this.storage.getItem("user");
|
||||
|
||||
this.user = userJson !== "undefined" ? new User(JSON.parse(userJson)) : null;
|
||||
|
||||
if(this.isUser()) {
|
||||
if (this.isUser()) {
|
||||
this.auth = true;
|
||||
}
|
||||
}
|
||||
|
@ -36,10 +35,21 @@ export default class Session {
|
|||
this.storage = window.localStorage;
|
||||
}
|
||||
|
||||
setToken(token) {
|
||||
applyToken(token) {
|
||||
if (!token) {
|
||||
this.deleteToken();
|
||||
return false;
|
||||
}
|
||||
|
||||
this.session_token = token;
|
||||
this.storage.setItem("session_token", token);
|
||||
Api.defaults.headers.common["X-Session-Token"] = token;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
setToken(token) {
|
||||
this.storage.setItem("session_token", token);
|
||||
return this.applyToken(token);
|
||||
}
|
||||
|
||||
getToken() {
|
||||
|
@ -49,7 +59,7 @@ export default class Session {
|
|||
deleteToken() {
|
||||
this.session_token = null;
|
||||
this.storage.removeItem("session_token");
|
||||
Api.defaults.headers.common["X-Session-Token"] = "";
|
||||
delete Api.defaults.headers.common["X-Session-Token"];
|
||||
this.deleteUser();
|
||||
}
|
||||
|
||||
|
@ -108,7 +118,7 @@ export default class Session {
|
|||
login(email, password) {
|
||||
this.deleteToken();
|
||||
|
||||
return Api.post("session", { email: email, password: password }).then(
|
||||
return Api.post("session", {email: email, password: password}).then(
|
||||
(result) => {
|
||||
this.setToken(result.data.token);
|
||||
this.setUser(new User(result.data.user));
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import Api from "common/api";
|
||||
import Event from "pubsub-js";
|
||||
|
||||
export default {
|
||||
|
@ -40,7 +40,7 @@
|
|||
},
|
||||
methods: {
|
||||
submit() {
|
||||
console.log("SUBMIT");
|
||||
// DO NOTHING
|
||||
},
|
||||
startImport() {
|
||||
this.started = Date.now();
|
||||
|
@ -51,7 +51,7 @@
|
|||
|
||||
const ctx = this;
|
||||
|
||||
axios.post('/api/v1/import').then(function () {
|
||||
Api.post('import').then(function () {
|
||||
Event.publish("alert.success", "Import complete");
|
||||
ctx.busy = false;
|
||||
ctx.completed = 100;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import Api from "common/api";
|
||||
import Event from "pubsub-js";
|
||||
|
||||
export default {
|
||||
|
@ -40,7 +40,7 @@
|
|||
},
|
||||
methods: {
|
||||
submit() {
|
||||
console.log("SUBMIT");
|
||||
// DO NOTHING
|
||||
},
|
||||
startIndexing() {
|
||||
this.started = Date.now();
|
||||
|
@ -51,7 +51,7 @@
|
|||
|
||||
const ctx = this;
|
||||
|
||||
axios.post('/api/v1/index').then(function () {
|
||||
Api.post('index').then(function () {
|
||||
Event.publish("alert.success", "Indexing complete");
|
||||
ctx.busy = false;
|
||||
ctx.completed = 100;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import Api from "common/api";
|
||||
import Event from "pubsub-js";
|
||||
|
||||
export default {
|
||||
|
@ -48,7 +48,7 @@
|
|||
},
|
||||
methods: {
|
||||
submit() {
|
||||
// console.log("SUBMIT");
|
||||
// DO NOTHING
|
||||
},
|
||||
uploadDialog() {
|
||||
this.$refs.upload.click();
|
||||
|
@ -80,7 +80,7 @@
|
|||
|
||||
formData.append('files', file);
|
||||
|
||||
await axios.post('/api/v1/upload/' + ctx.started,
|
||||
await Api.post('upload/' + ctx.started,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
|
@ -99,7 +99,7 @@
|
|||
this.indexing = true;
|
||||
const ctx = this;
|
||||
|
||||
axios.post('/api/v1/import/upload/' + this.started).then(function () {
|
||||
Api.post('import/upload/' + this.started).then(function () {
|
||||
Event.publish("alert.success", "Upload complete");
|
||||
ctx.busy = false;
|
||||
ctx.indexing = false;
|
||||
|
|
|
@ -35,7 +35,7 @@ describe('common/session', () => {
|
|||
it('should set, get and delete user', () => {
|
||||
const storage = window.localStorage;
|
||||
const session = new Session(storage);
|
||||
assert.equal(session.user.ID, undefined);
|
||||
assert.equal(session.user, null);
|
||||
const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"};
|
||||
const user = new User(values);
|
||||
session.setUser(user);
|
||||
|
|
|
@ -48,6 +48,11 @@ type CreateAlbumParams struct {
|
|||
// POST /api/v1/albums
|
||||
func CreateAlbum(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.POST("/albums", func(c *gin.Context) {
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
var params CreateAlbumParams
|
||||
|
||||
if err := c.BindJSON(¶ms); err != nil {
|
||||
|
@ -73,6 +78,11 @@ func CreateAlbum(router *gin.RouterGroup, conf *config.Config) {
|
|||
// uuid: string Album UUID
|
||||
func LikeAlbum(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.POST("/albums/:uuid/like", func(c *gin.Context) {
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
search := photoprism.NewSearch(conf.OriginalsPath(), conf.Db())
|
||||
|
||||
album, err := search.FindAlbumByUUID(c.Param("uuid"))
|
||||
|
@ -95,6 +105,11 @@ func LikeAlbum(router *gin.RouterGroup, conf *config.Config) {
|
|||
// uuid: string Album UUID
|
||||
func DislikeAlbum(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.DELETE("/albums/:uuid/like", func(c *gin.Context) {
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
search := photoprism.NewSearch(conf.OriginalsPath(), conf.Db())
|
||||
|
||||
album, err := search.FindAlbumByUUID(c.Param("uuid"))
|
||||
|
|
|
@ -8,24 +8,24 @@ import (
|
|||
|
||||
func TestGetAlbums(t *testing.T) {
|
||||
t.Run("successful request", func(t *testing.T) {
|
||||
app, router, ctx := NewApiTest()
|
||||
GetAlbums(router, ctx)
|
||||
app, router, conf := NewApiTest()
|
||||
GetAlbums(router, conf)
|
||||
result := PerformRequest(app, "GET", "/api/v1/albums?count=10")
|
||||
|
||||
assert.Equal(t, http.StatusOK, result.Code)
|
||||
})
|
||||
t.Run("invalid request", func(t *testing.T) {
|
||||
app, router, ctx := NewApiTest()
|
||||
GetAlbums(router, ctx)
|
||||
app, router, conf := NewApiTest()
|
||||
GetAlbums(router, conf)
|
||||
result := PerformRequest(app, "GET", "/api/v1/albums?xxx=10")
|
||||
t.Log(result.Body)
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, result.Code)
|
||||
})
|
||||
t.Run("invalid request", func(t *testing.T) {
|
||||
app, router, ctx := NewApiTest()
|
||||
app, router, conf := NewApiTest()
|
||||
t.Log(router)
|
||||
t.Log(ctx)
|
||||
t.Log(conf)
|
||||
result := PerformRequest(app, "GET", "/api/v1/albums?xxx=10")
|
||||
t.Log(result.Body)
|
||||
|
||||
|
@ -47,9 +47,9 @@ func TestLikeAlbum(t *testing.T) {
|
|||
|
||||
func TestDislikeAlbum(t *testing.T) {
|
||||
t.Run("dislike not existing album", func(t *testing.T) {
|
||||
app, router, ctx := NewApiTest()
|
||||
app, router, conf := NewApiTest()
|
||||
|
||||
LikeAlbum(router, ctx)
|
||||
LikeAlbum(router, conf)
|
||||
|
||||
result := PerformRequest(app, "DELETE", "/api/v1/albums/5678/like")
|
||||
t.Log(result.Body)
|
||||
|
|
|
@ -33,6 +33,11 @@ func Import(router *gin.RouterGroup, conf *config.Config) {
|
|||
return
|
||||
}
|
||||
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
path := conf.ImportPath()
|
||||
|
||||
|
|
|
@ -44,6 +44,11 @@ func GetLabels(router *gin.RouterGroup, conf *config.Config) {
|
|||
// slug: string Label slug name
|
||||
func LikeLabel(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.POST("/labels/:slug/like", func(c *gin.Context) {
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
search := photoprism.NewSearch(conf.OriginalsPath(), conf.Db())
|
||||
|
||||
label, err := search.FindLabelBySlug(c.Param("slug"))
|
||||
|
@ -66,6 +71,11 @@ func LikeLabel(router *gin.RouterGroup, conf *config.Config) {
|
|||
// slug: string Label slug name
|
||||
func DislikeLabel(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.DELETE("/labels/:slug/like", func(c *gin.Context) {
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
search := photoprism.NewSearch(conf.OriginalsPath(), conf.Db())
|
||||
|
||||
label, err := search.FindLabelBySlug(c.Param("slug"))
|
||||
|
|
|
@ -58,6 +58,11 @@ func GetPhotos(router *gin.RouterGroup, conf *config.Config) {
|
|||
// id: int Photo ID as returned by the API
|
||||
func LikePhoto(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.POST("/photos/:id/like", func(c *gin.Context) {
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
search := photoprism.NewSearch(conf.OriginalsPath(), conf.Db())
|
||||
photoID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
|
||||
|
@ -87,6 +92,11 @@ func LikePhoto(router *gin.RouterGroup, conf *config.Config) {
|
|||
// id: int Photo ID as returned by the API
|
||||
func DislikePhoto(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.DELETE("/photos/:id/like", func(c *gin.Context) {
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
search := photoprism.NewSearch(conf.OriginalsPath(), conf.Db())
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
|
||||
|
|
|
@ -58,14 +58,18 @@ func DeleteSession(router *gin.RouterGroup, conf *config.Config) {
|
|||
|
||||
// Returns true, if user doesn't have a valid session token
|
||||
func Unauthorized(c *gin.Context, conf *config.Config) bool {
|
||||
// Always return false if site is public
|
||||
if conf.Public() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Get session token from HTTP header
|
||||
token := c.GetHeader("X-Session-Token")
|
||||
gc := conf.Cache()
|
||||
log.Debugf("X-Session-Token: %s", token)
|
||||
|
||||
// Check if session token is valid
|
||||
gc := conf.Cache()
|
||||
_, found := gc.Get(token)
|
||||
|
||||
return found
|
||||
return !found
|
||||
}
|
||||
|
|
|
@ -10,6 +10,11 @@ import (
|
|||
// GET /api/v1/settings
|
||||
func GetSettings(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.GET("/settings", func(c *gin.Context) {
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
result := conf.Settings()
|
||||
|
||||
c.JSON(http.StatusOK, result)
|
||||
|
@ -19,6 +24,11 @@ func GetSettings(router *gin.RouterGroup, conf *config.Config) {
|
|||
// POST /api/v1/settings
|
||||
func SaveSettings(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.POST("/settings", func(c *gin.Context) {
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "saved"})
|
||||
|
|
|
@ -33,6 +33,8 @@ func NewTestParams() *Params {
|
|||
testDataPath := testDataPath(assetsPath)
|
||||
|
||||
c := &Params{
|
||||
Public: true,
|
||||
ReadOnly: false,
|
||||
DarktableBin: "/usr/bin/darktable-cli",
|
||||
AssetsPath: assetsPath,
|
||||
CachePath: testDataPath + "/cache",
|
||||
|
|
Loading…
Reference in a new issue