2020-08-09 19:33:47 +00:00
package util
import (
2020-11-14 10:39:18 +00:00
"crypto/rand"
"encoding/hex"
2021-06-19 04:51:10 +00:00
"github.com/bouncepaw/mycorrhiza/files"
2021-05-09 10:42:12 +00:00
"log"
2020-08-31 17:52:26 +00:00
"net/http"
2021-01-28 19:07:21 +00:00
"regexp"
2020-08-09 19:33:47 +00:00
"strings"
2021-06-16 12:27:28 +00:00
2021-10-05 20:10:28 +00:00
"github.com/bouncepaw/mycomarkup/v3/util"
2021-06-16 12:27:28 +00:00
"github.com/bouncepaw/mycorrhiza/cfg"
2020-08-09 19:33:47 +00:00
)
2021-06-14 21:07:31 +00:00
// PrepareRq strips the trailing / in rq.URL.Path. In the future it might do more stuff for making all request structs uniform.
2021-05-09 10:42:12 +00:00
func PrepareRq ( rq * http . Request ) {
rq . URL . Path = strings . TrimSuffix ( rq . URL . Path , "/" )
}
2021-06-19 04:51:10 +00:00
// ShorterPath is used by handlerList to display shorter path to the files. It
// simply strips the hyphae directory name.
2020-08-09 19:33:47 +00:00
func ShorterPath ( path string ) string {
2021-06-19 04:51:10 +00:00
if strings . HasPrefix ( path , files . HyphaeDir ( ) ) {
tmp := strings . TrimPrefix ( path , files . HyphaeDir ( ) )
2020-08-09 19:33:47 +00:00
if tmp == "" {
return ""
}
return tmp [ 1 : ]
}
return path
}
2020-08-31 17:52:26 +00:00
2021-03-05 12:20:51 +00:00
// HTTP404Page writes a 404 error in the status, needed when no content is found on the page.
func HTTP404Page ( w http . ResponseWriter , page string ) {
w . Header ( ) . Set ( "Content-Type" , "text/html;charset=utf-8" )
w . WriteHeader ( http . StatusNotFound )
2021-06-14 21:07:31 +00:00
_ , _ = w . Write ( [ ] byte ( page ) )
2021-03-05 12:20:51 +00:00
}
2020-08-31 17:52:26 +00:00
// HTTP200Page wraps some frequently used things for successful 200 responses.
func HTTP200Page ( w http . ResponseWriter , page string ) {
w . Header ( ) . Set ( "Content-Type" , "text/html;charset=utf-8" )
w . WriteHeader ( http . StatusOK )
2021-06-14 21:07:31 +00:00
_ , _ = w . Write ( [ ] byte ( page ) )
2020-08-31 17:52:26 +00:00
}
2020-10-03 16:56:56 +00:00
2021-06-14 21:07:31 +00:00
// RandomString generates a random string of the given length. It is cryptographically secure to some extent.
2020-11-14 10:39:18 +00:00
func RandomString ( n int ) ( string , error ) {
bytes := make ( [ ] byte , n )
if _ , err := rand . Read ( bytes ) ; err != nil {
return "" , err
}
return hex . EncodeToString ( bytes ) , nil
}
2021-01-10 11:58:02 +00:00
2021-06-14 21:07:31 +00:00
// BeautifulName makes the ugly name beautiful by replacing _ with spaces and using title case.
2021-01-10 11:58:02 +00:00
func BeautifulName ( uglyName string ) string {
2021-06-14 21:07:31 +00:00
// Why not reuse
return util . BeautifulName ( uglyName )
2021-01-10 11:58:02 +00:00
}
2021-01-28 19:07:21 +00:00
// CanonicalName makes sure the `name` is canonical. A name is canonical if it is lowercase and all spaces are replaced with underscores.
func CanonicalName ( name string ) string {
2021-06-14 21:07:31 +00:00
return util . CanonicalName ( name )
2021-01-28 19:07:21 +00:00
}
2021-06-14 21:07:31 +00:00
// hyphaPattern is a pattern which all hypha names must match.
var hyphaPattern = regexp . MustCompile ( ` [^?!:#@><*|"'&% { }]+ ` )
2021-01-28 19:07:21 +00:00
2021-06-14 21:07:31 +00:00
var usernamePattern = regexp . MustCompile ( ` [^?!:#@><*|"'&% { }/]+ ` )
2021-04-19 16:39:25 +00:00
2021-01-28 19:07:21 +00:00
// IsCanonicalName checks if the `name` is canonical.
func IsCanonicalName ( name string ) bool {
2021-06-14 21:07:31 +00:00
return hyphaPattern . MatchString ( name )
2021-01-28 19:07:21 +00:00
}
2021-04-19 16:39:25 +00:00
2021-06-14 21:07:31 +00:00
// IsPossibleUsername is true if the given username is ok. Same as IsCanonicalName, but cannot have / in it and cannot be equal to "anon" or "wikimind"
2021-04-19 16:39:25 +00:00
func IsPossibleUsername ( username string ) bool {
2021-07-14 21:30:30 +00:00
return username != "anon" && username != "wikimind" && usernameIsWhiteListed ( username ) && usernamePattern . MatchString ( strings . TrimSpace ( username ) )
}
func usernameIsWhiteListed ( username string ) bool {
if ! cfg . UseWhiteList {
return true
}
for _ , allowedUsername := range cfg . WhiteList {
if allowedUsername == username {
return true
}
}
return false
2021-04-19 16:39:25 +00:00
}
2021-05-09 10:42:12 +00:00
// HyphaNameFromRq extracts hypha name from http request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha".
func HyphaNameFromRq ( rq * http . Request , actions ... string ) string {
p := rq . URL . Path
for _ , action := range actions {
if strings . HasPrefix ( p , "/" + action + "/" ) {
return CanonicalName ( strings . TrimPrefix ( p , "/" + action + "/" ) )
}
}
2021-06-14 21:07:31 +00:00
log . Println ( "HyphaNameFromRq: this request is invalid, fall back to home hypha" )
2021-05-09 10:42:12 +00:00
return cfg . HomeHypha
}
2021-07-02 12:02:42 +00:00
// FormData is a convenient struct for passing user input and errors to HTML
// forms and showing to the user.
type FormData struct {
err error
fields map [ string ] string
}
2021-10-01 17:12:16 +00:00
// NewFormData constructs empty form data instance.
2021-07-02 12:02:42 +00:00
func NewFormData ( ) FormData {
return FormData {
err : nil ,
fields : map [ string ] string { } ,
}
}
2021-10-01 17:12:16 +00:00
// FormDataFromRequest extracts a form data from request, using a set of keys.
2021-07-02 12:02:42 +00:00
func FormDataFromRequest ( r * http . Request , keys [ ] string ) FormData {
formData := NewFormData ( )
for _ , key := range keys {
formData . Put ( key , r . FormValue ( key ) )
}
return formData
}
2021-10-01 17:12:16 +00:00
// HasError is true if there is indeed an error.
2021-07-02 12:02:42 +00:00
func ( f FormData ) HasError ( ) bool {
return f . err != nil
}
2021-10-01 17:12:16 +00:00
// Error returns an error text or empty string, if there are no errors in form data.
2021-07-02 12:02:42 +00:00
func ( f FormData ) Error ( ) string {
if f . err == nil {
return ""
}
return f . err . Error ( )
}
2021-10-01 17:12:16 +00:00
// WithError puts an error into form data and returns itself.
2021-07-02 12:02:42 +00:00
func ( f FormData ) WithError ( err error ) FormData {
f . err = err
return f
}
2021-10-01 17:12:16 +00:00
// Get accesses form data with a key
2021-07-02 12:02:42 +00:00
func ( f FormData ) Get ( key string ) string {
return f . fields [ key ]
}
2021-10-01 17:34:56 +00:00
// Put writes a form value for provided key
2021-07-02 12:02:42 +00:00
func ( f FormData ) Put ( key , value string ) {
f . fields [ key ] = value
}