changing default asset path

This commit is contained in:
Roland Osborne 2022-03-10 23:57:27 -08:00
parent 54b9737cd6
commit 7e824d19b3
13 changed files with 123 additions and 45 deletions

View File

@ -273,13 +273,6 @@ paths:
- account
description: Check if any public accounts are available
operationId: get-account-available
parameters:
- name: public
in: query
description: for open access accounts
required: false
schema:
type: boolean
responses:
'200':
description: available public accounts

View File

@ -2,6 +2,7 @@ package databag
import (
"os"
"errors"
"net/http"
"crypto/sha256"
"encoding/hex"
@ -10,11 +11,23 @@ import (
)
func AddAccount(w http.ResponseWriter, r *http.Request) {
var token *store.AccountToken
token, res := BearerAccountToken(r);
if res != nil || token.TokenType != APP_TOKENCREATE {
ErrResponse(w, http.StatusUnauthorized, res)
if r.Header.Get("Authorization") == "" {
if available, err := getAvailableAccounts(); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
} else if available == 0 {
ErrResponse(w, http.StatusForbidden, errors.New("no open accounts available"))
return
}
} else {
var err error
token, err = BearerAccountToken(r);
if err != nil || token.TokenType != APP_TOKENCREATE {
ErrResponse(w, http.StatusUnauthorized, err)
return
}
}
username, password, ret := BasicCredentials(r);
@ -23,6 +36,17 @@ func AddAccount(w http.ResponseWriter, r *http.Request) {
return
}
// check if username is taken
var count int64
if err := store.DB.Model(&store.Account{}).Where("username = ?", username).Count(&count).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err);
return
}
if count != 0 {
ErrResponse(w, http.StatusConflict, errors.New("username already taken"))
return
}
// generate account key
privateKey, publicKey, keyType, err := GenerateRsaKeyPair()
if err != nil {
@ -42,7 +66,7 @@ func AddAccount(w http.ResponseWriter, r *http.Request) {
fingerprint := hex.EncodeToString(hash[:])
// create path for account data
path := getStrConfigValue(CONFIG_ASSETPATH, ".") + "/" + fingerprint
path := getStrConfigValue(CONFIG_ASSETPATH, APP_DEFAULTPATH) + "/" + fingerprint
if err := os.Mkdir(path, os.ModePerm); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
}
@ -68,9 +92,11 @@ func AddAccount(w http.ResponseWriter, r *http.Request) {
if res := tx.Create(&account).Error; res != nil {
return res;
}
if token != nil {
if res := tx.Delete(token).Error; res != nil {
return res;
}
}
return nil;
});
if err != nil {

View File

@ -70,7 +70,7 @@ func AddChannelTopicAsset(w http.ResponseWriter, r *http.Request) {
// save new file
id := uuid.New().String()
path := getStrConfigValue(CONFIG_ASSETPATH, ".") + "/" + channelSlot.Account.Guid + "/" + id
path := getStrConfigValue(CONFIG_ASSETPATH, APP_DEFAULTPATH) + "/" + channelSlot.Account.Guid + "/" + id
if err := r.ParseMultipartForm(32 << 20); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return

View File

@ -7,21 +7,28 @@ import (
func GetAccountAvailable(w http.ResponseWriter, r *http.Request) {
public := r.FormValue("public") == "true"
open := getBoolConfigValue(CONFIG_OPENACCESS, true)
limit := getNumConfigValue(CONFIG_ACCOUNTLIMIT, 16)
var count int64
if err := store.DB.Model(&store.Account{}).Count(&count).Error; err != nil {
available, err := getAvailableAccounts()
if err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
var available int64
if (!public || open) && limit > count {
available = limit - count
}
WriteResponse(w, &available)
}
func getAvailableAccounts() (available int64, err error) {
open := getBoolConfigValue(CONFIG_OPENACCESS, true)
limit := getNumConfigValue(CONFIG_ACCOUNTLIMIT, 16)
var count int64
if err = store.DB.Model(&store.Account{}).Count(&count).Error; err != nil {
return
}
if open && limit > count {
available = limit - count
}
return
}

View File

@ -1,6 +1,7 @@
package databag
import (
"errors"
"net/http"
"databag/internal/store"
)
@ -10,23 +11,33 @@ type accountUsername struct {
}
func GetAccountUsername(w http.ResponseWriter, r *http.Request) {
var token *store.AccountToken
token, err := BearerAccountToken(r);
if err != nil || (token.TokenType != "create" && token.TokenType != "reset") {
LogMsg("invalid token")
w.WriteHeader(http.StatusUnauthorized)
if r.Header.Get("Authorization") == "" {
if available, err := getAvailableAccounts(); err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
} else if available == 0 {
ErrResponse(w, http.StatusUnauthorized, errors.New("no open accounts available"))
return
}
} else {
var err error
token, err = BearerAccountToken(r);
if err != nil || token.TokenType != APP_TOKENCREATE {
ErrResponse(w, http.StatusUnauthorized, err)
return
}
}
username := r.URL.Query().Get("username")
if username == "" {
LogMsg("invalid username")
w.WriteHeader(http.StatusBadRequest)
ErrResponse(w, http.StatusBadRequest, errors.New("specify a username"))
return
}
var accounts []accountUsername;
err = store.DB.Model(&store.Account{}).Where("username = ?", username).Find(&accounts).Error
err := store.DB.Model(&store.Account{}).Where("username = ?", username).Find(&accounts).Error
if err != nil {
LogMsg("failed to query accounts")
w.WriteHeader(http.StatusInternalServerError)

View File

@ -42,7 +42,7 @@ func GetChannelTopicAsset(w http.ResponseWriter, r *http.Request) {
}
// construct file path
path := getStrConfigValue(CONFIG_ASSETPATH, ".") + "/" + act.Guid + "/" + asset.AssetId
path := getStrConfigValue(CONFIG_ASSETPATH, APP_DEFAULTPATH) + "/" + act.Guid + "/" + asset.AssetId
http.ServeFile(w, r, path)
}

View File

@ -78,7 +78,7 @@ func RemoveAccount(w http.ResponseWriter, r *http.Request) {
}
// delete asset files
path := getStrConfigValue(CONFIG_ASSETPATH, ".") + "/" + account.Guid
path := getStrConfigValue(CONFIG_ASSETPATH, APP_DEFAULTPATH) + "/" + account.Guid
if err = os.RemoveAll(path); err != nil {
ErrMsg(err)
}

View File

@ -98,7 +98,7 @@ func RemoveNodeAccount(w http.ResponseWriter, r *http.Request) {
}
// delete asset files
path := getStrConfigValue(CONFIG_ASSETPATH, ".") + "/" + account.Guid
path := getStrConfigValue(CONFIG_ASSETPATH, APP_DEFAULTPATH) + "/" + account.Guid
if err = os.RemoveAll(path); err != nil {
ErrMsg(err)
}

View File

@ -47,6 +47,7 @@ const APP_QUEUEAUDIO = "audio"
const APP_QUEUEVIDEO = "video"
const APP_QUEUEPHOTO = "photo"
const APP_QUEUEDEFAULT = ""
const APP_DEFAULTPATH = "./asset"
func AppCardStatus(status string) bool {
if status == APP_CARDPENDING {

View File

@ -60,7 +60,7 @@ func AccountLogin(r *http.Request) (*store.Account, error) {
return account, nil
}
func BearerAccountToken(r *http.Request) (store.AccountToken, error) {
func BearerAccountToken(r *http.Request) (*store.AccountToken, error) {
// parse bearer authentication
auth := r.Header.Get("Authorization")
@ -69,12 +69,12 @@ func BearerAccountToken(r *http.Request) (store.AccountToken, error) {
// find token record
var accountToken store.AccountToken
if err := store.DB.Preload("Account").Where("token = ?", token).First(&accountToken).Error; err != nil {
return accountToken, err
return nil, err
}
if accountToken.Expires < time.Now().Unix() {
return accountToken, errors.New("expired token")
return nil, errors.New("expired token")
}
return accountToken, nil
return &accountToken, nil
}
func BearerAppToken(r *http.Request, detail bool) (*store.Account, int, error) {

View File

@ -13,7 +13,7 @@ func garbageCollect(act *store.Account) {
defer garbageSync.Unlock()
// get all asset files
dir := getStrConfigValue(CONFIG_ASSETPATH, ".") + "/" + act.Guid
dir := getStrConfigValue(CONFIG_ASSETPATH, APP_DEFAULTPATH) + "/" + act.Guid
files, err := os.ReadDir(dir)
if err != nil {
ErrMsg(err)

View File

@ -89,7 +89,7 @@ func transcodeDefault() {
func transcodeAsset(asset *store.Asset) {
// prepare script path
data := getStrConfigValue(CONFIG_ASSETPATH, ".")
data := getStrConfigValue(CONFIG_ASSETPATH, APP_DEFAULTPATH)
script := getStrConfigValue(CONFIG_SCRIPTPATH, ".")
re := regexp.MustCompile("^[a-zA-Z0-9_]*$")

View File

@ -1,14 +1,54 @@
import React, { useState } from 'react'
import React, { useState, useEffect } from 'react'
import login from './login.png';
import { Input, Button } from 'antd';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import 'antd/dist/antd.css';
const FETCH_TIMEOUT = 15000;
function checkResponse(response) {
if(response.status >= 400 && response.status < 600) {
throw new Error(response.url + " failed");
}
}
async function fetchWithTimeout(url, options) {
return Promise.race([
fetch(url, options).catch(err => { throw new Error(url + ' failed'); }),
new Promise((_, reject) => setTimeout(() => reject(new Error(url + ' timeout')), FETCH_TIMEOUT))
]);
}
async function getAvailable() {
let available = await fetchWithTimeout("/account/available", { method: 'GET', timeout: FETCH_TIMEOUT } );
checkResponse(available);
return await available.json()
}
function App() {
const [available, setAvailable] = useState(0)
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
useEffect(() => {
getAvailable().then(a => {
setAvailable(a)
console.log(a)
}).catch(err => {
console.log(err)
})
}, [])
const Create = () => {
if (available > 0) {
return <Button type="link" onClick={onCreate} style={{ marginTop: '4px', color: '#000044' }}>Create Account</Button>
}
return <></>
}
const onLogin = () => {
console.log(username)
console.log(password)
@ -31,7 +71,7 @@ function App() {
<Input.Password size="large" onChange={(e) => setPassword(e.target.value)} placeholder="password" prefix={<LockOutlined />} style={{ marginTop: '16px' }} />
<Button type="primary" onClick={onLogin} style={{ alignSelf: 'center', marginTop: '16px', width: '33%' }}>Sign In</Button>
</div>
<Button type="link" onClick={onCreate} style={{ marginTop: '4px', color: '#000044' }}>Create Account</Button>
<Create />
</div>
</div>
);