DB Updates :)
Former-commit-id: e9795cfca39aab57f4a4b604c65633958ff22e46 [formerly 7dd93e46eb6915a387dc64500a3fe7f6f955643b] [formerly ffa277f1605e46bb8c914464b1223fe029d579d8 [formerly a04ff87bf9
]]
Former-commit-id: ffa472fd3b1534f64a1c343864564bbc0290714b [formerly 7074f824d7d7dd3cd74b884c9f3e96834f662394]
Former-commit-id: 4b1e0324de6065fd4daec25d463d3756588b92d8
pull/726/head
parent
4b602be5e3
commit
764289e52f
|
@ -22,7 +22,7 @@
|
||||||
<!-- Add to home screen for Windows -->
|
<!-- Add to home screen for Windows -->
|
||||||
<meta name="msapplication-TileImage" content="{{ .BaseURL }}/static/img/icons/msapplication-icon-144x144.png">
|
<meta name="msapplication-TileImage" content="{{ .BaseURL }}/static/img/icons/msapplication-icon-144x144.png">
|
||||||
<meta name="msapplication-TileColor" content="#2979ff">
|
<meta name="msapplication-TileColor" content="#2979ff">
|
||||||
<% for (var chunk of webpack.compilation.chunks) {
|
<% for (var chunk of webpack.chunks) {
|
||||||
for (var file of chunk.files) {
|
for (var file of chunk.files) {
|
||||||
if (file.match(/\.(js|css)$/)) { %>
|
if (file.match(/\.(js|css)$/)) { %>
|
||||||
<link rel="preload" href="{{ .BaseURL }}/<%= file %>" as="<%= file.match(/\.css$/)?'style':'script' %>"><% }}} %>
|
<link rel="preload" href="{{ .BaseURL }}/<%= file %>" as="<%= file.match(/\.css$/)?'style':'script' %>"><% }}} %>
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package bolt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/asdine/storm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigStore struct {
|
||||||
|
DB *storm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConfigStore) Get(name string, to interface{}) error {
|
||||||
|
return c.DB.Get("config", name, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConfigStore) Save(name string, from interface{}) error {
|
||||||
|
return c.DB.Set("config", name, from)
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package bolt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/asdine/storm"
|
||||||
|
fm "github.com/hacdias/filemanager"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ShareStore struct {
|
||||||
|
DB *storm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ShareStore) Get(hash string) (*fm.ShareLink, error) {
|
||||||
|
var v *fm.ShareLink
|
||||||
|
err := s.DB.One("Hash", hash, &v)
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ShareStore) GetByPath(hash string) ([]*fm.ShareLink, error) {
|
||||||
|
var v []*fm.ShareLink
|
||||||
|
err := s.DB.Find("Path", hash, &v)
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ShareStore) Gets(hash string) ([]*fm.ShareLink, error) {
|
||||||
|
var v []*fm.ShareLink
|
||||||
|
err := s.DB.All(&v)
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ShareStore) Save(l *fm.ShareLink) error {
|
||||||
|
return s.DB.Save(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ShareStore) Delete(hash string) error {
|
||||||
|
return s.DB.DeleteStruct(&fm.ShareLink{Hash: hash})
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package bolt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/asdine/storm"
|
||||||
|
fm "github.com/hacdias/filemanager"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UsersStore struct {
|
||||||
|
DB *storm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UsersStore) Get(id int) (*fm.User, error) {
|
||||||
|
var us *fm.User
|
||||||
|
err := u.DB.One("ID", id, us)
|
||||||
|
if err == storm.ErrNotFound {
|
||||||
|
return nil, fm.ErrUserNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &fm.User{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UsersStore) Gets() ([]*fm.User, error) {
|
||||||
|
var us []*fm.User
|
||||||
|
err := u.DB.All(us)
|
||||||
|
return us, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UsersStore) Update(us *fm.User, fields ...string) error {
|
||||||
|
if len(fields) == 0 {
|
||||||
|
return u.Save(us)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
val := reflect.ValueOf(us).Elem().FieldByName(field).Interface()
|
||||||
|
if err := u.DB.UpdateField(us, field, val); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UsersStore) Save(us *fm.User) error {
|
||||||
|
return u.DB.Save(us)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UsersStore) Delete(id int) error {
|
||||||
|
return u.DB.DeleteStruct(&fm.User{ID: id})
|
||||||
|
}
|
28
file.go
28
file.go
|
@ -24,12 +24,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errInvalidOption = errors.New("Invalid option")
|
ErrInvalidOption = errors.New("Invalid option")
|
||||||
)
|
)
|
||||||
|
|
||||||
// File contains the information about a particular file or directory.
|
// File contains the information about a particular file or directory.
|
||||||
type File struct {
|
type File struct {
|
||||||
// Indicates the Kind of view on the front-end (listing, editor or preview).
|
// Indicates the Kind of view on the front-end (Listing, editor or preview).
|
||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
// The name of the file.
|
// The name of the file.
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -54,19 +54,19 @@ type File struct {
|
||||||
// Stores the content of a text file.
|
// Stores the content of a text file.
|
||||||
Content string `json:"content,omitempty"`
|
Content string `json:"content,omitempty"`
|
||||||
|
|
||||||
*listing `json:",omitempty"`
|
*Listing `json:",omitempty"`
|
||||||
|
|
||||||
Metadata string `json:"metadata,omitempty"`
|
Metadata string `json:"metadata,omitempty"`
|
||||||
Language string `json:"language,omitempty"`
|
Language string `json:"language,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// A listing is the context used to fill out a template.
|
// A Listing is the context used to fill out a template.
|
||||||
type listing struct {
|
type Listing struct {
|
||||||
// The items (files and folders) in the path.
|
// The items (files and folders) in the path.
|
||||||
Items []*File `json:"items"`
|
Items []*File `json:"items"`
|
||||||
// The number of directories in the listing.
|
// The number of directories in the Listing.
|
||||||
NumDirs int `json:"numDirs"`
|
NumDirs int `json:"numDirs"`
|
||||||
// The number of files (items that aren't directories) in the listing.
|
// The number of files (items that aren't directories) in the Listing.
|
||||||
NumFiles int `json:"numFiles"`
|
NumFiles int `json:"numFiles"`
|
||||||
// Which sorting order is used.
|
// Which sorting order is used.
|
||||||
Sort string `json:"sort"`
|
Sort string `json:"sort"`
|
||||||
|
@ -166,7 +166,7 @@ func (i *File) GetListing(u *User, r *http.Request) error {
|
||||||
fileinfos = append(fileinfos, i)
|
fileinfos = append(fileinfos, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
i.listing = &listing{
|
i.Listing = &Listing{
|
||||||
Items: fileinfos,
|
Items: fileinfos,
|
||||||
NumDirs: dirCount,
|
NumDirs: dirCount,
|
||||||
NumFiles: fileCount,
|
NumFiles: fileCount,
|
||||||
|
@ -304,7 +304,7 @@ func (i File) Checksum(algo string) (string, error) {
|
||||||
case "sha512":
|
case "sha512":
|
||||||
h = sha512.New()
|
h = sha512.New()
|
||||||
default:
|
default:
|
||||||
return "", errInvalidOption
|
return "", ErrInvalidOption
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = io.Copy(h, file)
|
_, err = io.Copy(h, file)
|
||||||
|
@ -321,7 +321,7 @@ func (i File) CanBeEdited() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplySort applies the sort order using .Order and .Sort
|
// ApplySort applies the sort order using .Order and .Sort
|
||||||
func (l listing) ApplySort() {
|
func (l Listing) ApplySort() {
|
||||||
// Check '.Order' to know how to sort
|
// Check '.Order' to know how to sort
|
||||||
if l.Order == "desc" {
|
if l.Order == "desc" {
|
||||||
switch l.Sort {
|
switch l.Sort {
|
||||||
|
@ -350,10 +350,10 @@ func (l listing) ApplySort() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement sorting for listing
|
// Implement sorting for Listing
|
||||||
type byName listing
|
type byName Listing
|
||||||
type bySize listing
|
type bySize Listing
|
||||||
type byModified listing
|
type byModified Listing
|
||||||
|
|
||||||
// By Name
|
// By Name
|
||||||
func (l byName) Len() int {
|
func (l byName) Len() int {
|
||||||
|
|
132
filemanager.go
132
filemanager.go
|
@ -61,6 +61,7 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
rice "github.com/GeertJohan/go.rice"
|
rice "github.com/GeertJohan/go.rice"
|
||||||
"github.com/asdine/storm"
|
"github.com/asdine/storm"
|
||||||
|
@ -71,17 +72,14 @@ import (
|
||||||
// FileManager is a file manager instance. It should be creating using the
|
// FileManager is a file manager instance. It should be creating using the
|
||||||
// 'New' function and not directly.
|
// 'New' function and not directly.
|
||||||
type FileManager struct {
|
type FileManager struct {
|
||||||
// The BoltDB database for this instance.
|
// Job cron.
|
||||||
db *storm.DB
|
Cron *cron.Cron
|
||||||
|
|
||||||
// The key used to sign the JWT tokens.
|
// The key used to sign the JWT tokens.
|
||||||
key []byte
|
Key []byte
|
||||||
|
|
||||||
// The static assets.
|
// The static assets.
|
||||||
assets *rice.Box
|
Assets *rice.Box
|
||||||
|
|
||||||
// Job cron.
|
|
||||||
cron *cron.Cron
|
|
||||||
|
|
||||||
// PrefixURL is a part of the URL that is already trimmed from the request URL before it
|
// PrefixURL is a part of the URL that is already trimmed from the request URL before it
|
||||||
// arrives to our handlers. It may be useful when using File Manager as a middleware
|
// arrives to our handlers. It may be useful when using File Manager as a middleware
|
||||||
|
@ -103,66 +101,42 @@ type FileManager struct {
|
||||||
// The Default User needed to build the New User page.
|
// The Default User needed to build the New User page.
|
||||||
DefaultUser *User
|
DefaultUser *User
|
||||||
|
|
||||||
// Users is a map with the different configurations for each user.
|
|
||||||
Users map[string]*User
|
|
||||||
|
|
||||||
// A map of events to a slice of commands.
|
// A map of events to a slice of commands.
|
||||||
Commands map[string][]string
|
Commands map[string][]string
|
||||||
|
|
||||||
Store *Store
|
Store *Store
|
||||||
}
|
}
|
||||||
|
|
||||||
type Store struct {
|
|
||||||
Users *UsersStore
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command is a command function.
|
// Command is a command function.
|
||||||
type Command func(r *http.Request, m *FileManager, u *User) error
|
type Command func(r *http.Request, m *FileManager, u *User) error
|
||||||
|
|
||||||
/*
|
func (m *FileManager) Load() error {
|
||||||
|
|
||||||
// New creates a new File Manager instance. If 'database' file already
|
|
||||||
// exists, it will load the users from there. Otherwise, a new user
|
|
||||||
// will be created using the 'base' variable. The 'base' User should
|
|
||||||
// not have the Password field hashed.
|
|
||||||
func New(database string, base User) (*FileManager, error) {
|
|
||||||
// Creates a new File Manager instance with the Users
|
// Creates a new File Manager instance with the Users
|
||||||
// map and Assets box.
|
// map and Assets box.
|
||||||
m := &FileManager{
|
m.Assets = rice.MustFindBox("./assets/dist")
|
||||||
Users: map[string]*User{},
|
m.Cron = cron.New()
|
||||||
cron: cron.New(),
|
|
||||||
assets: rice.MustFindBox("./assets/dist"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tries to open a database on the location provided. This
|
|
||||||
// function will automatically create a new one if it doesn't
|
|
||||||
// exist.
|
|
||||||
db, err := storm.Open(database)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tries to get the encryption key from the database.
|
// Tries to get the encryption key from the database.
|
||||||
// If it doesn't exist, create a new one of 256 bits.
|
// If it doesn't exist, create a new one of 256 bits.
|
||||||
err = db.Get("config", "key", &m.key)
|
err := m.Store.Config.Get("key", &m.Key)
|
||||||
if err != nil && err == storm.ErrNotFound {
|
if err != nil && err == ErrNotExist {
|
||||||
var bytes []byte
|
var bytes []byte
|
||||||
bytes, err = generateRandomBytes(64)
|
bytes, err = GenerateRandomBytes(64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.key = bytes
|
m.Key = bytes
|
||||||
err = db.Set("config", "key", m.key)
|
err = m.Store.Config.Save("key", m.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tries to get the event commands from the database.
|
// Tries to get the event commands from the database.
|
||||||
// If they don't exist, initialize them.
|
// If they don't exist, initialize them.
|
||||||
err = db.Get("config", "commands", &m.Commands)
|
err = m.Store.Config.Get("commands", &m.Commands)
|
||||||
if err != nil && err == storm.ErrNotFound {
|
if err != nil && err == storm.ErrNotFound {
|
||||||
m.Commands = map[string][]string{
|
m.Commands = map[string][]string{
|
||||||
"before_save": {},
|
"before_save": {},
|
||||||
|
@ -170,35 +144,29 @@ func New(database string, base User) (*FileManager, error) {
|
||||||
"before_publish": {},
|
"before_publish": {},
|
||||||
"after_publish": {},
|
"after_publish": {},
|
||||||
}
|
}
|
||||||
err = db.Set("config", "commands", m.Commands)
|
err = m.Store.Config.Save("commands", m.Commands)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tries to fetch the users from the database and if there are
|
// Tries to fetch the users from the database.
|
||||||
// any, add them to the current File Manager instance.
|
users, err := m.Store.Users.Gets()
|
||||||
var users []User
|
|
||||||
err = db.All(&users)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
for i := range users {
|
|
||||||
m.Users[users[i].Username] = &users[i]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no users in the database, it creates a new one
|
// If there are no users in the database, it creates a new one
|
||||||
// based on 'base' User that must be provided by the function caller.
|
// based on 'base' User that must be provided by the function caller.
|
||||||
if len(users) == 0 {
|
if len(users) == 0 {
|
||||||
u := base
|
u := *m.DefaultUser
|
||||||
u.Username = "admin"
|
u.Username = "admin"
|
||||||
|
|
||||||
// Hashes the password.
|
// Hashes the password.
|
||||||
u.Password, err = hashPassword("admin")
|
u.Password, err = HashPassword("admin")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The first user must be an administrator.
|
// The first user must be an administrator.
|
||||||
|
@ -209,27 +177,20 @@ func New(database string, base User) (*FileManager, error) {
|
||||||
u.AllowPublish = true
|
u.AllowPublish = true
|
||||||
|
|
||||||
// Saves the user to the database.
|
// Saves the user to the database.
|
||||||
if err := db.Save(&u); err != nil {
|
if err := m.Store.Users.Save(&u); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Users[u.Username] = &u
|
m.DefaultUser.Username = ""
|
||||||
|
m.DefaultUser.Password = ""
|
||||||
|
|
||||||
|
m.Cron.AddFunc("@hourly", m.ShareCleaner)
|
||||||
|
m.Cron.Start()
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attaches db to this File Manager instance.
|
|
||||||
m.db = db
|
|
||||||
|
|
||||||
// Create the default user, making a copy of the base.
|
|
||||||
base.Username = ""
|
|
||||||
base.Password = ""
|
|
||||||
m.DefaultUser = &base
|
|
||||||
|
|
||||||
m.cron.AddFunc("@hourly", m.shareCleaner)
|
|
||||||
m.cron.Start()
|
|
||||||
|
|
||||||
return m, nil
|
|
||||||
} */
|
|
||||||
|
|
||||||
// RootURL returns the actual URL where
|
// RootURL returns the actual URL where
|
||||||
// File Manager interface can be accessed.
|
// File Manager interface can be accessed.
|
||||||
func (m FileManager) RootURL() string {
|
func (m FileManager) RootURL() string {
|
||||||
|
@ -291,24 +252,19 @@ func (m *FileManager) Attach(s StaticGen) error {
|
||||||
|
|
||||||
m.StaticGen = s
|
m.StaticGen = s
|
||||||
|
|
||||||
// TODO: Save...
|
err = m.Store.Config.Get("staticgen_"+s.Name(), s)
|
||||||
/* err := m.db.Get("staticgen", "hugo", h)
|
if err == ErrNotExist {
|
||||||
if err != nil && err == storm.ErrNotFound {
|
return m.Store.Config.Save("staticgen_"+s.Name(), s)
|
||||||
err = m.db.Set("staticgen", "hugo", *h)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// shareCleaner removes sharing links that are no longer active.
|
// ShareCleaner removes sharing links that are no longer active.
|
||||||
// This function is set to run periodically.
|
// This function is set to run periodically.
|
||||||
func (m FileManager) shareCleaner() {
|
func (m FileManager) ShareCleaner() {
|
||||||
var links []shareLink
|
|
||||||
|
|
||||||
// Get all links.
|
// Get all links.
|
||||||
err := m.db.All(&links)
|
links, err := m.Store.Share.Gets()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
return
|
return
|
||||||
|
@ -317,13 +273,13 @@ func (m FileManager) shareCleaner() {
|
||||||
// Find the expired ones.
|
// Find the expired ones.
|
||||||
for i := range links {
|
for i := range links {
|
||||||
if links[i].Expires && links[i].ExpireDate.Before(time.Now()) {
|
if links[i].Expires && links[i].ExpireDate.Before(time.Now()) {
|
||||||
err = m.db.DeleteStruct(&links[i])
|
err = m.Store.Share.Delete(links[i].Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} */
|
}
|
||||||
|
|
||||||
// Runner runs the commands for a certain event type.
|
// Runner runs the commands for a certain event type.
|
||||||
func (m FileManager) Runner(event string, path string) error {
|
func (m FileManager) Runner(event string, path string) error {
|
||||||
|
|
44
http/auth.go
44
http/auth.go
|
@ -1,14 +1,11 @@
|
||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
|
|
||||||
jwt "github.com/dgrijalva/jwt-go"
|
jwt "github.com/dgrijalva/jwt-go"
|
||||||
"github.com/dgrijalva/jwt-go/request"
|
"github.com/dgrijalva/jwt-go/request"
|
||||||
fm "github.com/hacdias/filemanager"
|
fm "github.com/hacdias/filemanager"
|
||||||
|
@ -33,13 +30,13 @@ func authHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, er
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the user exists.
|
// Checks if the user exists.
|
||||||
u, ok := c.Users[cred.Username]
|
u, err := c.Store.Users.Get(cred.ID)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return http.StatusForbidden, nil
|
return http.StatusForbidden, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the password is correct.
|
// Checks if the password is correct.
|
||||||
if !checkPasswordHash(cred.Password, u.Password) {
|
if !fm.CheckPasswordHash(cred.Password, u.Password) {
|
||||||
return http.StatusForbidden, nil
|
return http.StatusForbidden, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +83,7 @@ func printToken(c *fm.Context, w http.ResponseWriter) (int, error) {
|
||||||
|
|
||||||
// Creates the token and signs it.
|
// Creates the token and signs it.
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
signed, err := token.SignedString(c.key)
|
signed, err := token.SignedString(c.Key)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
|
@ -127,7 +124,7 @@ func validateAuth(c *fm.Context, r *http.Request) (bool, *fm.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
keyFunc := func(token *jwt.Token) (interface{}, error) {
|
keyFunc := func(token *jwt.Token) (interface{}, error) {
|
||||||
return c.key, nil
|
return c.Key, nil
|
||||||
}
|
}
|
||||||
var claims claims
|
var claims claims
|
||||||
token, err := request.ParseFromRequestWithClaims(r,
|
token, err := request.ParseFromRequestWithClaims(r,
|
||||||
|
@ -140,38 +137,11 @@ func validateAuth(c *fm.Context, r *http.Request) (bool, *fm.User) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
u, ok := c.Users[claims.User.Username]
|
u, err := c.Store.Users.Get(claims.User.ID)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
c.User = u
|
c.User = u
|
||||||
return true, u
|
return true, u
|
||||||
}
|
}
|
||||||
|
|
||||||
// hashPassword generates an hash from a password using bcrypt.
|
|
||||||
func hashPassword(password string) (string, error) {
|
|
||||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
||||||
return string(bytes), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkPasswordHash compares a password with an hash to check if they match.
|
|
||||||
func checkPasswordHash(password, hash string) bool {
|
|
||||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateRandomBytes returns securely generated random bytes.
|
|
||||||
// It will return an error if the system's secure random
|
|
||||||
// number generator fails to function correctly, in which
|
|
||||||
// case the caller should not continue.
|
|
||||||
func generateRandomBytes(n int) ([]byte, error) {
|
|
||||||
b := make([]byte, n)
|
|
||||||
_, err := rand.Read(b)
|
|
||||||
// Note that err == nil only if we read len(b) bytes.
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ func TestRenewHandler(t *testing.T) {
|
||||||
// First, we have to make an auth request to get the user authenticated,
|
// First, we have to make an auth request to get the user authenticated,
|
||||||
r, err := http.NewRequest("POST", "/api/auth/get", strings.NewReader(defaultCredentials))
|
r, err := http.NewRequest("POST", "/api/auth/get", strings.NewReader(defaultCredentials))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(fm.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
@ -60,7 +60,7 @@ func TestRenewHandler(t *testing.T) {
|
||||||
// Test renew authorization via Authorization Header.
|
// Test renew authorization via Authorization Header.
|
||||||
r, err = http.NewRequest("GET", "/api/auth/renew", nil)
|
r, err = http.NewRequest("GET", "/api/auth/renew", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(fm.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Header.Set("Authorization", "Bearer "+token)
|
r.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
@ -74,7 +74,7 @@ func TestRenewHandler(t *testing.T) {
|
||||||
// Test renew authorization via cookie field.
|
// Test renew authorization via cookie field.
|
||||||
r, err = http.NewRequest("GET", "/api/auth/renew", nil)
|
r, err = http.NewRequest("GET", "/api/auth/renew", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(fm.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.AddCookie(&http.Cookie{
|
r.AddCookie(&http.Cookie{
|
47
http/http.go
47
http/http.go
|
@ -2,7 +2,6 @@ package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -13,21 +12,10 @@ import (
|
||||||
fm "github.com/hacdias/filemanager"
|
fm "github.com/hacdias/filemanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errUserExist = errors.New("user already exists")
|
|
||||||
errUserNotExist = errors.New("user does not exist")
|
|
||||||
errEmptyRequest = errors.New("request body is empty")
|
|
||||||
errEmptyPassword = errors.New("password is empty")
|
|
||||||
errEmptyUsername = errors.New("username is empty")
|
|
||||||
errEmptyScope = errors.New("scope is empty")
|
|
||||||
errWrongDataType = errors.New("wrong data type")
|
|
||||||
errInvalidUpdateField = errors.New("invalid field to update")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ServeHTTP is the main entry point of this HTML application.
|
// ServeHTTP is the main entry point of this HTML application.
|
||||||
func ServeHTTP(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func ServeHTTP(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
// Checks if the URL contains the baseURL and strips it. Otherwise, it just
|
// Checks if the URL contains the baseURL and strips it. Otherwise, it just
|
||||||
// returns a 404 error because we're not supposed to be here!
|
// returns a 404 fm.Error because we're not supposed to be here!
|
||||||
p := strings.TrimPrefix(r.URL.Path, c.BaseURL)
|
p := strings.TrimPrefix(r.URL.Path, c.BaseURL)
|
||||||
|
|
||||||
if len(p) >= len(r.URL.Path) && c.BaseURL != "" {
|
if len(p) >= len(r.URL.Path) && c.BaseURL != "" {
|
||||||
|
@ -41,7 +29,7 @@ func ServeHTTP(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, erro
|
||||||
if r.URL.Path == "/sw.js" {
|
if r.URL.Path == "/sw.js" {
|
||||||
return renderFile(
|
return renderFile(
|
||||||
c, w,
|
c, w,
|
||||||
c.assets.MustString("sw.js"),
|
c.Assets.MustString("sw.js"),
|
||||||
"application/javascript",
|
"application/javascript",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -83,7 +71,7 @@ func ServeHTTP(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, erro
|
||||||
|
|
||||||
return renderFile(
|
return renderFile(
|
||||||
c, w,
|
c, w,
|
||||||
c.assets.MustString("index.html"),
|
c.Assets.MustString("index.html"),
|
||||||
"text/html",
|
"text/html",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -91,13 +79,13 @@ func ServeHTTP(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, erro
|
||||||
// staticHandler handles the static assets path.
|
// staticHandler handles the static assets path.
|
||||||
func staticHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func staticHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
if r.URL.Path != "/static/manifest.json" {
|
if r.URL.Path != "/static/manifest.json" {
|
||||||
http.FileServer(c.assets.HTTPBox()).ServeHTTP(w, r)
|
http.FileServer(c.Assets.HTTPBox()).ServeHTTP(w, r)
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderFile(
|
return renderFile(
|
||||||
c, w,
|
c, w,
|
||||||
c.assets.MustString("static/manifest.json"),
|
c.Assets.MustString("static/manifest.json"),
|
||||||
"application/json",
|
"application/json",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -141,7 +129,7 @@ func apiHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, err
|
||||||
var err error
|
var err error
|
||||||
c.File, err = fm.GetInfo(r.URL, c.FileManager, c.User)
|
c.File, err = fm.GetInfo(r.URL, c.FileManager, c.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, false), err
|
return ErrorToHTTP(err, false), err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +165,7 @@ func checksumHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
query := r.URL.Query().Get("algo")
|
query := r.URL.Query().Get("algo")
|
||||||
|
|
||||||
val, err := c.File.Checksum(query)
|
val, err := c.File.Checksum(query)
|
||||||
if err == errInvalidOption {
|
if err == fm.ErrInvalidOption {
|
||||||
return http.StatusBadRequest, err
|
return http.StatusBadRequest, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
|
@ -211,7 +199,7 @@ func renderFile(c *fm.Context, w http.ResponseWriter, file string, contentType s
|
||||||
|
|
||||||
err := tpl.Execute(w, map[string]interface{}{
|
err := tpl.Execute(w, map[string]interface{}{
|
||||||
"BaseURL": c.RootURL(),
|
"BaseURL": c.RootURL(),
|
||||||
"StaticGen": c.staticgen,
|
"StaticGen": c.StaticGen.Name(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
|
@ -221,12 +209,11 @@ func renderFile(c *fm.Context, w http.ResponseWriter, file string, contentType s
|
||||||
}
|
}
|
||||||
|
|
||||||
func sharePage(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func sharePage(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
var s shareLink
|
s, err := c.Store.Share.Get(r.URL.Path)
|
||||||
err := c.db.One("Hash", r.URL.Path, &s)
|
|
||||||
if err == storm.ErrNotFound {
|
if err == storm.ErrNotFound {
|
||||||
return renderFile(
|
return renderFile(
|
||||||
c, w,
|
c, w,
|
||||||
c.assets.MustString("static/share/404.html"),
|
c.Assets.MustString("static/share/404.html"),
|
||||||
"text/html",
|
"text/html",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -236,10 +223,10 @@ func sharePage(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Expires && s.ExpireDate.Before(time.Now()) {
|
if s.Expires && s.ExpireDate.Before(time.Now()) {
|
||||||
c.db.DeleteStruct(&s)
|
c.Store.Share.Delete(s.Hash)
|
||||||
return renderFile(
|
return renderFile(
|
||||||
c, w,
|
c, w,
|
||||||
c.assets.MustString("static/share/404.html"),
|
c.Assets.MustString("static/share/404.html"),
|
||||||
"text/html",
|
"text/html",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -248,10 +235,10 @@ func sharePage(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, erro
|
||||||
|
|
||||||
info, err := os.Stat(s.Path)
|
info, err := os.Stat(s.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, false), err
|
return ErrorToHTTP(err, false), err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.File = &file{
|
c.File = &fm.File{
|
||||||
Path: s.Path,
|
Path: s.Path,
|
||||||
Name: info.Name(),
|
Name: info.Name(),
|
||||||
ModTime: info.ModTime(),
|
ModTime: info.ModTime(),
|
||||||
|
@ -263,7 +250,7 @@ func sharePage(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, erro
|
||||||
dl := r.URL.Query().Get("dl")
|
dl := r.URL.Query().Get("dl")
|
||||||
|
|
||||||
if dl == "" || dl == "0" {
|
if dl == "" || dl == "0" {
|
||||||
tpl := template.Must(template.New("file").Parse(c.assets.MustString("static/share/index.html")))
|
tpl := template.Must(template.New("file").Parse(c.Assets.MustString("static/share/index.html")))
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
|
||||||
err := tpl.Execute(w, map[string]interface{}{
|
err := tpl.Execute(w, map[string]interface{}{
|
||||||
|
@ -303,8 +290,8 @@ func matchURL(first, second string) bool {
|
||||||
return strings.HasPrefix(first, second)
|
return strings.HasPrefix(first, second)
|
||||||
}
|
}
|
||||||
|
|
||||||
// errorToHTTP converts errors to HTTP Status Code.
|
// ErrorToHTTP converts errors to HTTP Status Code.
|
||||||
func errorToHTTP(err error, gone bool) int {
|
func ErrorToHTTP(err error, gone bool) int {
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
return http.StatusOK
|
return http.StatusOK
|
||||||
|
|
|
@ -64,9 +64,9 @@ func resourceHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
|
|
||||||
func resourceGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func resourceGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
// Gets the information of the directory/file.
|
// Gets the information of the directory/file.
|
||||||
f, err := getInfo(r.URL, c.FileManager, c.User)
|
f, err := fm.GetInfo(r.URL, c.FileManager, c.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, false), err
|
return ErrorToHTTP(err, false), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's a dir and the path doesn't end with a trailing slash,
|
// If it's a dir and the path doesn't end with a trailing slash,
|
||||||
|
@ -83,7 +83,7 @@ func resourceGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (
|
||||||
|
|
||||||
// Tries to get the file type.
|
// Tries to get the file type.
|
||||||
if err = f.GetFileType(true); err != nil {
|
if err = f.GetFileType(true); err != nil {
|
||||||
return errorToHTTP(err, true), err
|
return ErrorToHTTP(err, true), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve a preview if the file can't be edited or the
|
// Serve a preview if the file can't be edited or the
|
||||||
|
@ -97,7 +97,7 @@ func resourceGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (
|
||||||
f.Kind = "editor"
|
f.Kind = "editor"
|
||||||
|
|
||||||
// Tries to get the editor data.
|
// Tries to get the editor data.
|
||||||
if err = f.getEditor(); err != nil {
|
if err = f.GetEditor(); err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,11 +109,11 @@ func listingHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int,
|
||||||
f.Kind = "listing"
|
f.Kind = "listing"
|
||||||
|
|
||||||
// Tries to get the listing data.
|
// Tries to get the listing data.
|
||||||
if err := f.getListing(c, r); err != nil {
|
if err := f.GetListing(c.User, r); err != nil {
|
||||||
return errorToHTTP(err, true), err
|
return ErrorToHTTP(err, true), err
|
||||||
}
|
}
|
||||||
|
|
||||||
listing := f.listing
|
listing := f.Listing
|
||||||
|
|
||||||
// Defines the cookie scope.
|
// Defines the cookie scope.
|
||||||
cookieScope := c.RootURL()
|
cookieScope := c.RootURL()
|
||||||
|
@ -144,7 +144,7 @@ func resourceDeleteHandler(c *fm.Context, w http.ResponseWriter, r *http.Request
|
||||||
// Remove the file or folder.
|
// Remove the file or folder.
|
||||||
err := c.User.FileSystem.RemoveAll(r.URL.Path)
|
err := c.User.FileSystem.RemoveAll(r.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, true), err
|
return ErrorToHTTP(err, true), err
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.StatusOK, nil
|
return http.StatusOK, nil
|
||||||
|
@ -160,7 +160,7 @@ func resourcePostPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Reques
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discard any invalid upload before returning to avoid connection
|
// Discard any invalid upload before returning to avoid connection
|
||||||
// reset error.
|
// reset fm.Error.
|
||||||
defer func() {
|
defer func() {
|
||||||
io.Copy(ioutil.Discard, r.Body)
|
io.Copy(ioutil.Discard, r.Body)
|
||||||
}()
|
}()
|
||||||
|
@ -175,13 +175,13 @@ func resourcePostPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Reques
|
||||||
|
|
||||||
// Otherwise we try to create the directory.
|
// Otherwise we try to create the directory.
|
||||||
err := c.User.FileSystem.Mkdir(r.URL.Path, 0776)
|
err := c.User.FileSystem.Mkdir(r.URL.Path, 0776)
|
||||||
return errorToHTTP(err, false), err
|
return ErrorToHTTP(err, false), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If using POST method, we are trying to create a new file so it is not
|
// If using POST method, we are trying to create a new file so it is not
|
||||||
// desirable to override an already existent file. Thus, we check
|
// desirable to ovfm.Erride an already existent file. Thus, we check
|
||||||
// if the file already exists. If so, we just return a 409 Conflict.
|
// if the file already exists. If so, we just return a 409 Conflict.
|
||||||
if r.Method == http.MethodPost && r.Header.Get("Action") != "override" {
|
if r.Method == http.MethodPost && r.Header.Get("Action") != "ovfm.Erride" {
|
||||||
if _, err := c.User.FileSystem.Stat(r.URL.Path); err == nil {
|
if _, err := c.User.FileSystem.Stat(r.URL.Path); err == nil {
|
||||||
return http.StatusConflict, errors.New("There is already a file on that path")
|
return http.StatusConflict, errors.New("There is already a file on that path")
|
||||||
}
|
}
|
||||||
|
@ -190,20 +190,20 @@ func resourcePostPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Reques
|
||||||
// Create/Open the file.
|
// Create/Open the file.
|
||||||
f, err := c.User.FileSystem.OpenFile(r.URL.Path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0776)
|
f, err := c.User.FileSystem.OpenFile(r.URL.Path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0776)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, false), err
|
return ErrorToHTTP(err, false), err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
// Copies the new content for the file.
|
// Copies the new content for the file.
|
||||||
_, err = io.Copy(f, r.Body)
|
_, err = io.Copy(f, r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, false), err
|
return ErrorToHTTP(err, false), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the info about the file.
|
// Gets the info about the file.
|
||||||
fi, err := f.Stat()
|
fi, err := f.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, false), err
|
return ErrorToHTTP(err, false), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this instance has a Static Generator and handles publishing
|
// Check if this instance has a Static Generator and handles publishing
|
||||||
|
@ -242,7 +242,7 @@ func resourcePublishSchedule(c *fm.Context, w http.ResponseWriter, r *http.Reque
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.cron.AddFunc(t.Format("05 04 15 02 01 *"), func() {
|
c.Cron.AddFunc(t.Format("05 04 15 02 01 *"), func() {
|
||||||
_, err := resourcePublish(c, w, r)
|
_, err := resourcePublish(c, w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
|
@ -283,7 +283,7 @@ func resourcePatchHandler(c *fm.Context, w http.ResponseWriter, r *http.Request)
|
||||||
action := r.Header.Get("Action")
|
action := r.Header.Get("Action")
|
||||||
dst, err := url.QueryUnescape(dst)
|
dst, err := url.QueryUnescape(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, true), err
|
return ErrorToHTTP(err, true), err
|
||||||
}
|
}
|
||||||
|
|
||||||
src := r.URL.Path
|
src := r.URL.Path
|
||||||
|
@ -298,7 +298,7 @@ func resourcePatchHandler(c *fm.Context, w http.ResponseWriter, r *http.Request)
|
||||||
err = c.User.FileSystem.Rename(src, dst)
|
err = c.User.FileSystem.Rename(src, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorToHTTP(err, true), err
|
return ErrorToHTTP(err, true), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// displayMode obtains the display mode from the Cookie.
|
// displayMode obtains the display mode from the Cookie.
|
||||||
|
|
|
@ -27,7 +27,7 @@ type option struct {
|
||||||
func parsePutSettingsRequest(r *http.Request) (*modifySettingsRequest, error) {
|
func parsePutSettingsRequest(r *http.Request) (*modifySettingsRequest, error) {
|
||||||
// Checks if the request body is empty.
|
// Checks if the request body is empty.
|
||||||
if r.Body == nil {
|
if r.Body == nil {
|
||||||
return nil, errEmptyRequest
|
return nil, fm.ErrEmptyRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses the request body and checks if it's well formed.
|
// Parses the request body and checks if it's well formed.
|
||||||
|
@ -39,7 +39,7 @@ func parsePutSettingsRequest(r *http.Request) (*modifySettingsRequest, error) {
|
||||||
|
|
||||||
// Checks if the request type is right.
|
// Checks if the request type is right.
|
||||||
if mod.What != "settings" {
|
if mod.What != "settings" {
|
||||||
return nil, errWrongDataType
|
return nil, fm.ErrWrongDataType
|
||||||
}
|
}
|
||||||
|
|
||||||
return mod, nil
|
return mod, nil
|
||||||
|
@ -103,9 +103,10 @@ func settingsPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusBadRequest, err
|
return http.StatusBadRequest, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the commands.
|
// Update the commands.
|
||||||
if mod.Which == "commands" {
|
if mod.Which == "commands" {
|
||||||
if err := c.db.Set("config", "commands", mod.Data.Commands); err != nil {
|
if err := c.Store.Config.Save("commands", mod.Data.Commands); err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +121,7 @@ func settingsPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.db.Set("staticgen", c.staticgen, c.StaticGen)
|
err = c.Store.Config.Save("staticgen_"+c.StaticGen.Name(), c.StaticGen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,6 @@ import (
|
||||||
fm "github.com/hacdias/filemanager"
|
fm "github.com/hacdias/filemanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
type shareLink struct {
|
|
||||||
Hash string `json:"hash" storm:"id,index"`
|
|
||||||
Path string `json:"path" storm:"index"`
|
|
||||||
Expires bool `json:"expires"`
|
|
||||||
ExpireDate time.Time `json:"expireDate"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func shareHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func shareHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
r.URL.Path = sanitizeURL(r.URL.Path)
|
r.URL.Path = sanitizeURL(r.URL.Path)
|
||||||
|
|
||||||
|
@ -36,12 +29,8 @@ func shareHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, e
|
||||||
}
|
}
|
||||||
|
|
||||||
func shareGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func shareGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
var (
|
path := filepath.Join(string(c.User.FileSystem), r.URL.Path)
|
||||||
s []*shareLink
|
s, err := c.Store.Share.GetByPath(path)
|
||||||
path = filepath.Join(string(c.User.FileSystem), r.URL.Path)
|
|
||||||
)
|
|
||||||
|
|
||||||
err := c.db.Find("Path", path, &s)
|
|
||||||
if err == storm.ErrNotFound {
|
if err == storm.ErrNotFound {
|
||||||
return http.StatusNotFound, nil
|
return http.StatusNotFound, nil
|
||||||
}
|
}
|
||||||
|
@ -52,7 +41,7 @@ func shareGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
|
|
||||||
for i, link := range s {
|
for i, link := range s {
|
||||||
if link.Expires && link.ExpireDate.Before(time.Now()) {
|
if link.Expires && link.ExpireDate.Before(time.Now()) {
|
||||||
c.db.DeleteStruct(&shareLink{Hash: link.Hash})
|
c.Store.Share.Delete(link.Hash)
|
||||||
s = append(s[:i], s[i+1:]...)
|
s = append(s[:i], s[i+1:]...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +52,7 @@ func shareGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
func sharePostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func sharePostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
path := filepath.Join(string(c.User.FileSystem), r.URL.Path)
|
path := filepath.Join(string(c.User.FileSystem), r.URL.Path)
|
||||||
|
|
||||||
var s shareLink
|
var s fm.ShareLink
|
||||||
expire := r.URL.Query().Get("expires")
|
expire := r.URL.Query().Get("expires")
|
||||||
unit := r.URL.Query().Get("unit")
|
unit := r.URL.Query().Get("unit")
|
||||||
|
|
||||||
|
@ -75,14 +64,14 @@ func sharePostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes, err := generateRandomBytes(32)
|
bytes, err := fm.GenerateRandomBytes(32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
str := hex.EncodeToString(bytes)
|
str := hex.EncodeToString(bytes)
|
||||||
|
|
||||||
s = shareLink{
|
s = fm.ShareLink{
|
||||||
Path: path,
|
Path: path,
|
||||||
Hash: str,
|
Hash: str,
|
||||||
Expires: expire != "",
|
Expires: expire != "",
|
||||||
|
@ -109,8 +98,7 @@ func sharePostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (in
|
||||||
s.ExpireDate = time.Now().Add(add)
|
s.ExpireDate = time.Now().Add(add)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.db.Save(&s)
|
if err := c.Store.Share.Save(&s); err != nil {
|
||||||
if err != nil {
|
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,9 +106,7 @@ func sharePostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (in
|
||||||
}
|
}
|
||||||
|
|
||||||
func shareDeleteHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func shareDeleteHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
var s shareLink
|
s, err := c.Store.Share.Get(strings.TrimPrefix(r.URL.Path, "/"))
|
||||||
|
|
||||||
err := c.db.One("Hash", strings.TrimPrefix(r.URL.Path, "/"), &s)
|
|
||||||
if err == storm.ErrNotFound {
|
if err == storm.ErrNotFound {
|
||||||
return http.StatusNotFound, nil
|
return http.StatusNotFound, nil
|
||||||
}
|
}
|
||||||
|
@ -129,7 +115,7 @@ func shareDeleteHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.db.DeleteStruct(&s)
|
err = c.Store.Share.Delete(s.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
118
http/users.go
118
http/users.go
|
@ -9,7 +9,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/asdine/storm"
|
|
||||||
fm "github.com/hacdias/filemanager"
|
fm "github.com/hacdias/filemanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ func usersHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, e
|
||||||
|
|
||||||
// getUserID returns the id from the user which is present
|
// getUserID returns the id from the user which is present
|
||||||
// in the request url. If the url is invalid and doesn't
|
// in the request url. If the url is invalid and doesn't
|
||||||
// contain a valid ID, it returns an error.
|
// contain a valid ID, it returns an fm.Error.
|
||||||
func getUserID(r *http.Request) (int, error) {
|
func getUserID(r *http.Request) (int, error) {
|
||||||
// Obtains the ID in string from the URL and converts
|
// Obtains the ID in string from the URL and converts
|
||||||
// it into an integer.
|
// it into an integer.
|
||||||
|
@ -64,11 +63,11 @@ func getUserID(r *http.Request) (int, error) {
|
||||||
|
|
||||||
// getUser returns the user which is present in the request
|
// getUser returns the user which is present in the request
|
||||||
// body. If the body is empty or the JSON is invalid, it
|
// body. If the body is empty or the JSON is invalid, it
|
||||||
// returns an error.
|
// returns an fm.Error.
|
||||||
func getUser(r *http.Request) (*fm.User, string, error) {
|
func getUser(r *http.Request) (*fm.User, string, error) {
|
||||||
// Checks if the request body is empty.
|
// Checks if the request body is empty.
|
||||||
if r.Body == nil {
|
if r.Body == nil {
|
||||||
return nil, "", errEmptyRequest
|
return nil, "", fm.ErrEmptyRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses the request body and checks if it's well formed.
|
// Parses the request body and checks if it's well formed.
|
||||||
|
@ -80,7 +79,7 @@ func getUser(r *http.Request) (*fm.User, string, error) {
|
||||||
|
|
||||||
// Checks if the request type is right.
|
// Checks if the request type is right.
|
||||||
if mod.What != "user" {
|
if mod.What != "user" {
|
||||||
return nil, "", errWrongDataType
|
return nil, "", fm.ErrWrongDataType
|
||||||
}
|
}
|
||||||
|
|
||||||
return mod.Data, mod.Which, nil
|
return mod.Data, mod.Which, nil
|
||||||
|
@ -94,15 +93,15 @@ func usersGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
|
|
||||||
// Request for the listing of users.
|
// Request for the listing of users.
|
||||||
if r.URL.Path == "/" {
|
if r.URL.Path == "/" {
|
||||||
users := []User{}
|
users, err := c.Store.Users.Gets()
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
|
}
|
||||||
|
|
||||||
for _, user := range c.Users {
|
for _, u := range users {
|
||||||
// Copies the user info and removes its
|
// Removes the user password so it won't
|
||||||
// password so it won't be sent to the
|
// be sent to the front-end.
|
||||||
// front-end.
|
|
||||||
u := *user
|
|
||||||
u.Password = ""
|
u.Password = ""
|
||||||
users = append(users, u)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(users, func(i, j int) bool {
|
sort.Slice(users, func(i, j int) bool {
|
||||||
|
@ -117,21 +116,19 @@ func usersGetHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches for the user and prints the one who matches.
|
u, err := c.Store.Users.Get(id)
|
||||||
for _, user := range c.Users {
|
if err == fm.ErrExist {
|
||||||
if user.ID != id {
|
return http.StatusNotFound, err
|
||||||
continue
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
u := *user
|
|
||||||
u.Password = ""
|
u.Password = ""
|
||||||
return renderJSON(w, u)
|
return renderJSON(w, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there aren't any matches, return not found.
|
|
||||||
return http.StatusNotFound, errUserNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
func usersPostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func usersPostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
if r.URL.Path != "/" {
|
if r.URL.Path != "/" {
|
||||||
return http.StatusMethodNotAllowed, nil
|
return http.StatusMethodNotAllowed, nil
|
||||||
|
@ -144,17 +141,17 @@ func usersPostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (in
|
||||||
|
|
||||||
// Checks if username isn't empty.
|
// Checks if username isn't empty.
|
||||||
if u.Username == "" {
|
if u.Username == "" {
|
||||||
return http.StatusBadRequest, errEmptyUsername
|
return http.StatusBadRequest, fm.ErrEmptyUsername
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if filesystem isn't empty.
|
// Checks if filesystem isn't empty.
|
||||||
if u.FileSystem == "" {
|
if u.FileSystem == "" {
|
||||||
return http.StatusBadRequest, errEmptyScope
|
return http.StatusBadRequest, fm.ErrEmptyScope
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if password isn't empty.
|
// Checks if password isn't empty.
|
||||||
if u.Password == "" {
|
if u.Password == "" {
|
||||||
return http.StatusBadRequest, errEmptyPassword
|
return http.StatusBadRequest, fm.ErrEmptyPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
// The username, password and scope cannot be empty.
|
// The username, password and scope cannot be empty.
|
||||||
|
@ -164,7 +161,7 @@ func usersPostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (in
|
||||||
|
|
||||||
// Initialize rules if they're not initialized.
|
// Initialize rules if they're not initialized.
|
||||||
if u.Rules == nil {
|
if u.Rules == nil {
|
||||||
u.Rules = []*Rule{}
|
u.Rules = []*fm.Rule{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize commands if not initialized.
|
// Initialize commands if not initialized.
|
||||||
|
@ -183,7 +180,7 @@ func usersPostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (in
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hashes the password.
|
// Hashes the password.
|
||||||
pw, err := hashPassword(u.Password)
|
pw, err := fm.HashPassword(u.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
@ -191,18 +188,15 @@ func usersPostHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (in
|
||||||
u.Password = pw
|
u.Password = pw
|
||||||
|
|
||||||
// Saves the user to the database.
|
// Saves the user to the database.
|
||||||
err = c.db.Save(u)
|
err = c.Store.Users.Save(u)
|
||||||
if err == storm.ErrAlreadyExists {
|
if err == fm.ErrExist {
|
||||||
return http.StatusConflict, errUserExist
|
return http.StatusConflict, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saves the user to the memory.
|
|
||||||
c.Users[u.Username] = u
|
|
||||||
|
|
||||||
// Set the Location header and return.
|
// Set the Location header and return.
|
||||||
w.Header().Set("Location", "/users/"+strconv.Itoa(u.ID))
|
w.Header().Set("Location", "/users/"+strconv.Itoa(u.ID))
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
@ -243,23 +237,15 @@ func usersDeleteHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes the user from the database.
|
// Deletes the user from the database.
|
||||||
err = c.db.DeleteStruct(&User{ID: id})
|
err = c.Store.Users.Delete(id)
|
||||||
if err == storm.ErrNotFound {
|
if err == fm.ErrNotExist {
|
||||||
return http.StatusNotFound, errUserNotExist
|
return http.StatusNotFound, fm.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the user from the in-memory users map.
|
|
||||||
for _, user := range c.Users {
|
|
||||||
if user.ID == id {
|
|
||||||
delete(c.Users, user.Username)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return http.StatusOK, nil
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,12 +276,8 @@ func usersPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
if which == "partial" {
|
if which == "partial" {
|
||||||
c.User.CSS = u.CSS
|
c.User.CSS = u.CSS
|
||||||
c.User.Locale = u.Locale
|
c.User.Locale = u.Locale
|
||||||
err = c.db.UpdateField(&User{ID: c.User.ID}, "CSS", u.CSS)
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusInternalServerError, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.db.UpdateField(&User{ID: c.User.ID}, "Locale", u.Locale)
|
err = c.Store.Users.Update(c.User, "CSS", "Locale")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
@ -306,16 +288,15 @@ func usersPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
// Updates the Password.
|
// Updates the Password.
|
||||||
if which == "password" {
|
if which == "password" {
|
||||||
if u.Password == "" {
|
if u.Password == "" {
|
||||||
return http.StatusBadRequest, errEmptyPassword
|
return http.StatusBadRequest, fm.ErrEmptyPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
pw, err := hashPassword(u.Password)
|
c.User.Password, err = fm.HashPassword(u.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.User.Password = pw
|
err = c.Store.Users.Update(c.User, "Password")
|
||||||
err = c.db.UpdateField(&User{ID: c.User.ID}, "Password", pw)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
@ -325,17 +306,17 @@ func usersPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
|
|
||||||
// If can only be all.
|
// If can only be all.
|
||||||
if which != "all" {
|
if which != "all" {
|
||||||
return http.StatusBadRequest, errInvalidUpdateField
|
return http.StatusBadRequest, fm.ErrInvalidUpdateField
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if username isn't empty.
|
// Checks if username isn't empty.
|
||||||
if u.Username == "" {
|
if u.Username == "" {
|
||||||
return http.StatusBadRequest, errEmptyUsername
|
return http.StatusBadRequest, fm.ErrEmptyUsername
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if filesystem isn't empty.
|
// Checks if filesystem isn't empty.
|
||||||
if u.FileSystem == "" {
|
if u.FileSystem == "" {
|
||||||
return http.StatusBadRequest, errEmptyScope
|
return http.StatusBadRequest, fm.ErrEmptyScope
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the scope exists.
|
// Checks if the scope exists.
|
||||||
|
@ -345,7 +326,7 @@ func usersPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
|
|
||||||
// Initialize rules if they're not initialized.
|
// Initialize rules if they're not initialized.
|
||||||
if u.Rules == nil {
|
if u.Rules == nil {
|
||||||
u.Rules = []*Rule{}
|
u.Rules = []*fm.Rule{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize commands if not initialized.
|
// Initialize commands if not initialized.
|
||||||
|
@ -354,22 +335,20 @@ func usersPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the current saved user from the in-memory map.
|
// Gets the current saved user from the in-memory map.
|
||||||
var suser *User
|
suser, err := c.Store.Users.Get(id)
|
||||||
for _, user := range c.Users {
|
if err == fm.ErrNotExist {
|
||||||
if user.ID == id {
|
|
||||||
suser = user
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if suser == nil {
|
|
||||||
return http.StatusNotFound, nil
|
return http.StatusNotFound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
|
}
|
||||||
|
|
||||||
u.ID = id
|
u.ID = id
|
||||||
|
|
||||||
// Changes the password if the request wants it.
|
// Changes the password if the request wants it.
|
||||||
if u.Password != "" {
|
if u.Password != "" {
|
||||||
pw, err := hashPassword(u.Password)
|
pw, err := fm.HashPassword(u.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
@ -381,17 +360,10 @@ func usersPutHandler(c *fm.Context, w http.ResponseWriter, r *http.Request) (int
|
||||||
|
|
||||||
// Updates the whole User struct because we always are supposed
|
// Updates the whole User struct because we always are supposed
|
||||||
// to send a new entire object.
|
// to send a new entire object.
|
||||||
err = c.db.Save(u)
|
err = c.Store.Users.Update(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user changed the username, delete the old user
|
|
||||||
// from the in-memory user map.
|
|
||||||
if suser.Username != u.Username {
|
|
||||||
delete(c.Users, suser.Username)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Users[u.Username] = u
|
|
||||||
return http.StatusOK, nil
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ var (
|
||||||
|
|
||||||
// command handles the requests for VCS related commands: git, svn and mercurial
|
// command handles the requests for VCS related commands: git, svn and mercurial
|
||||||
func command(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func command(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
// Upgrades the connection to a websocket and checks for errors.
|
// Upgrades the connection to a websocket and checks for fm.Errors.
|
||||||
conn, err := upgrader.Upgrade(w, r, nil)
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -92,7 +92,7 @@ func command(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error)
|
||||||
cmd.Stderr = buff
|
cmd.Stderr = buff
|
||||||
cmd.Stdout = buff
|
cmd.Stdout = buff
|
||||||
|
|
||||||
// Starts the command and checks for errors.
|
// Starts the command and checks for fm.Errors.
|
||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
|
@ -241,7 +241,7 @@ func parseSearch(value string) *searchOptions {
|
||||||
|
|
||||||
// search searches for a file or directory.
|
// search searches for a file or directory.
|
||||||
func search(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
func search(c *fm.Context, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
// Upgrades the connection to a websocket and checks for errors.
|
// Upgrades the connection to a websocket and checks for fm.Errors.
|
||||||
conn, err := upgrader.Upgrade(w, r, nil)
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|
66
user.go
66
user.go
|
@ -1,12 +1,28 @@
|
||||||
package filemanager
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
"github.com/hacdias/fileutils"
|
"github.com/hacdias/fileutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrExist = errors.New("the resource already exists")
|
||||||
|
ErrNotExist = errors.New("the resource does not exist")
|
||||||
|
ErrEmptyRequest = errors.New("request body is empty")
|
||||||
|
ErrEmptyPassword = errors.New("password is empty")
|
||||||
|
ErrEmptyUsername = errors.New("username is empty")
|
||||||
|
ErrEmptyScope = errors.New("scope is empty")
|
||||||
|
ErrWrongDataType = errors.New("wrong data type")
|
||||||
|
ErrInvalidUpdateField = errors.New("invalid field to update")
|
||||||
|
)
|
||||||
|
|
||||||
// DefaultUser is used on New, when no 'base' user is provided.
|
// DefaultUser is used on New, when no 'base' user is provided.
|
||||||
var DefaultUser = User{
|
var DefaultUser = User{
|
||||||
AllowCommands: true,
|
AllowCommands: true,
|
||||||
|
@ -110,10 +126,24 @@ func (r *Regexp) MatchString(s string) bool {
|
||||||
return r.regexp.MatchString(s)
|
return r.regexp.MatchString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ShareLink struct {
|
||||||
|
Hash string `json:"hash" storm:"id,index"`
|
||||||
|
Path string `json:"path" storm:"index"`
|
||||||
|
Expires bool `json:"expires"`
|
||||||
|
ExpireDate time.Time `json:"expireDate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Store struct {
|
||||||
|
Users UsersStore
|
||||||
|
Config ConfigStore
|
||||||
|
Share ShareStore
|
||||||
|
}
|
||||||
|
|
||||||
type UsersStore interface {
|
type UsersStore interface {
|
||||||
Get(id int) (*User, error)
|
Get(id int) (*User, error)
|
||||||
Gets() ([]*User, error)
|
Gets() ([]*User, error)
|
||||||
Save(u *User, fields ...string) error
|
Save(u *User) error
|
||||||
|
Update(u *User, fields ...string) error
|
||||||
Delete(id int) error
|
Delete(id int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +153,36 @@ type ConfigStore interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ShareStore interface {
|
type ShareStore interface {
|
||||||
Get(hash string)
|
Get(hash string) (*ShareLink, error)
|
||||||
Save()
|
GetByPath(path string) ([]*ShareLink, error)
|
||||||
|
Gets() ([]*ShareLink, error)
|
||||||
|
Save(s *ShareLink) error
|
||||||
|
Delete(hash string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashPassword generates an hash from a password using bcrypt.
|
||||||
|
func HashPassword(password string) (string, error) {
|
||||||
|
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
return string(bytes), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckPasswordHash compares a password with an hash to check if they match.
|
||||||
|
func CheckPasswordHash(password, hash string) bool {
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateRandomBytes returns securely generated random bytes.
|
||||||
|
// It will return an fm.Error if the system's secure random
|
||||||
|
// number generator fails to function correctly, in which
|
||||||
|
// case the caller should not continue.
|
||||||
|
func GenerateRandomBytes(n int) ([]byte, error) {
|
||||||
|
b := make([]byte, n)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
// Note that err == nil only if we read len(b) bytes.
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue