backend

package
v0.0.0-...-f3ee4de Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 24, 2018 License: MPL-2.0 Imports: 51 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// VerifiedSubject auth email subject
	VerifiedSubject string
	// UnverifiedSubject auth email subject for first timers
	UnverifiedSubject string
)
View Source
var (
	CreateUser = `` /* 191-byte string literal not displayed */

	FindUSERByUsername = `FOR u IN users FILTER u.username == @username RETURN u`
	FindUSERByEmail    = `FOR u IN users FILTER u.email == @email RETURN u`
	FindUserByDetails  = `FOR u IN users FILTER u.email == @email && u.username == @username RETURN u`
)

Common DB Queries

View Source
var (
	// ErrInvalidToken ...
	ErrInvalidToken = errors.New("invalid base62 token")
	// ErrInvalidTokenVersion ...
	ErrInvalidTokenVersion = errors.New("invalid token version")
	// ErrBadKeyLength ...
	ErrBadKeyLength = errors.New("bad key length")
	// ErrExpiredToken ...
	ErrExpiredToken = errors.New("token has expired")
)
View Source
var (
	// DB central arangodb database for querying
	DB driver.Database
	// Users arangodb collection containing user data
	Users driver.Collection
	// Writs arangodb writ collection containing writs
	Writs driver.Collection
	// Logs arangodb log collection for storing the app's logs
	Logs driver.Collection
	// RateLimits arangodb ratelimits collection
	RateLimits driver.Collection
	// DBHealthTicker to see if the DB is still ok
	DBHealthTicker *time.Ticker
	// DBAlive does the db still live?
	DBAlive bool
)
View Source
var (
	SMTPAuth      smtp.Auth
	DKIMSignature dkim.Signature
	EmailConf     = struct {
		Address  string
		Server   string
		Port     string
		FromName string
		Email    string
		Password string
	}{}
	PrivateDKIMkey *rsa.PrivateKey
)

EmailSettings - email configuration and setup to send authtokens and stuff

View Source
var (
	// ErrIncompleteUser user is half baked, best get them in the DB before doing funny stuff
	ErrIncompleteUser = errors.New("cannot mutate a user that is incomplete or not in database")
	// ErrBadDBConnection bad database connection, try different details
	ErrBadDBConnection = StaticErrorResponse(500, "bad database connection error, try different details")
	// ErrIncompleteWrit someone probably tried to mutate a writ that is invalid or non existing (in db)
	ErrIncompleteWrit = StaticErrorResponse(500, `attempted to modify either an invalid writ, or one not in the db`)
	// ErrMissingTags writ is missing tags
	ErrMissingTags = errors.New(`writ doesn't have any tags, add some`)
	// ErrAuthorIsNoUser writ's author is persona non grata
	ErrAuthorIsNoUser = errors.New(`writ author is not a registered user`)
	// UnauthorizedError unauthorized request, cannot proceed
	UnauthorizedError = StaticErrorResponse(403, "unauthorized request, cannot proceed")
	// InvalidDetailsError invalid details, could not authorize user
	InvalidDetailsError = StaticErrorResponse(401, "invalid details, could not authorize user")
	// BadUsernameError invalid username, could not authorize user
	BadUsernameError = StaticErrorResponse(401, "invalid username, could not authorize user")
	// BadEmailError invalid email, could not authorize user
	BadEmailError = StaticErrorResponse(401, "invalid email, could not authorize user")
	// BadRequestError bad request, check details and try again
	BadRequestError = StaticErrorResponse(400, "bad request, check details and try again")
	// ServerDecodeError ran into trouble decoding your request
	ServerDecodeError = StaticErrorResponse(400, "ran into trouble decoding your request")
	// ServerDBError server error, could not complete your request
	ServerDBError = StaticErrorResponse(500, "server error, could not complete your request")
	// AlreadyLoggedIn user is logged in, but they tried to login again.
	AlreadyLoggedIn = StaticErrorResponse(203, "You're already logged in :D")
	// RateLimitingError somebody probably sent too many emails
	RateLimitingError = StaticErrorResponse(429, "ratelimiting: too many auth requests/emails, wait a bit and try again")
	// NoSuchWrit could not find a writ matching the query/request
	NoSuchWrit = StaticErrorResponse(404, "couldn't find a writ like that")
	// RequestQueryOverLimitMembers a member is requesting too many things at once
	RequestQueryOverLimitMembers = StaticErrorResponse(403, "requesting too many items at once, members >= 200")
	// RequestQueryOverLimit a viewer (non-member-user) is requesting too many things at once
	RequestQueryOverLimit = StaticErrorResponse(403, "requesting too many items at once, non-members >= 100")
	// SuccessMsg send a success response
	SuccessMsg = StaticResponse(203, "success!")
	// DeleteWritError there was trouble when attempting to delete a writ, prolly database/bad-input related
	DeleteWritError = StaticErrorResponse(500, "could not delete writ, maybe it didn't exist in the first place")
)

Errors for days

View Source
var (
	// AppName name of this application
	AppName string
	// AppDomain web domain of this application
	AppDomain string
	// DKIMKey private dkim key used for email signing
	DKIMKey []byte
	// DevMode run the app in production or dev-mode
	DevMode = false
	// Tokenator token generator/decoder
	Tokenator *Branca
	// Verinator token generator/decoder for verification codes only
	Verinator *Branca
	// MaintainerEmails the list of people to email if all hell breaks loose
	MaintainerEmails []string

	// AssetsDir path to all the servable static assets
	AssetsDir string
	// AppLocation where this application lives, it's used for self management
	AppLocation string
	// LocalIP is the IP of the machine/env the app is running on
	LocalIP string
	// StartupDate when the app started running
	StartupDate time.Time
	// LogQ server logging
	LogQ = []LogEntry{}

	// Server is the echo instance
	Server *echo.Echo

	// Conf contains various information about/for the setup
	Conf *Config

	// Cache serves memory cached (gzipped) static content
	Cache *tr.AssetCache
)
View Source
var (
	// RandomDictionary the character range of the randomBytes and randomString functions
	RandomDictionary = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
)

Functions

func AdminHandle

func AdminHandle(handle func(ctx, *User) error) func(ctx) error

AdminHandle create a GET route, accessible only to admin users

func AuthHandle

func AuthHandle(handle func(ctx, *User) error) func(ctx) error

AuthHandle create a GET route, accessible only to authenticated users

func GenerateAuthToken

func GenerateAuthToken(user *User, renew bool) (string, error)

GenerateAuthToken create a branca token

func GenerateVerifier

func GenerateVerifier(key string) string

GenerateVerifier create a branca token

func GetMD5Hash

func GetMD5Hash(text string) string

GetMD5Hash turn []byte into a MD5 hashed string

func Init

func Init()

Init start the backend server

func InitWrit

func InitWrit(w *Writ) error

InitWrit initialize a new writ

func Int64ToString

func Int64ToString(n int64) string

Int64ToString convert int64 to strings (for ports and stuff when you want to make json less stringy)

func IsUsernameAvailable

func IsUsernameAvailable(username string) bool

IsUsernameAvailable checks that the username is as of yet unused

func MD5Hash

func MD5Hash(data []byte) string

MD5Hash turn []byte into a MD5 hashed string

func MakeEmail

func MakeEmail() *mailyak.MailYak

MakeEmail builds a new mailyak instance

func Ping

func Ping(endpoint string) bool

Ping test any http endpoint

func Query

func Query(query string, vars obj) ([]obj, error)

Query query the app's DB with AQL, bindvars, and map that to an output

func QueryOne

func QueryOne(query string, vars obj, result interface{}) error

QueryOne query the app's DB with AQL, bindvars, and map that to an output

func RandBytes

func RandBytes(size int) []byte

RandBytes generate a random a []byte of a specific size

func RandStr

func RandStr(size int) string

RandStr generate a random string of a specific size

func RoleHandle

func RoleHandle(roles []Role, handle func(ctx, *User) error) func(ctx) error

RoleHandle create a GET route, accessible only to users with certain Roles

func SendEmail

func SendEmail(m *mailyak.MailYak) error

SendEmail send a dkim signed mailyak email

func SendErr

func SendErr(c ctx, code int, err string) error

SendErr send a msgpack encoded error message with this structure {err: "msg"}

func SendErrJSON

func SendErrJSON(c ctx, code int, err string) error

SendErrJSON send a json encoded error message like {"err": "msg"}

func SendJSON

func SendJSON(c ctx, code int, msg interface{}) error

SendJSON send a json encoded response with a status code

func SendMsgpack

func SendMsgpack(c ctx, code int, msg interface{}) error

SendMsgpack send a msgpack encoded response with a status code

func UnmarshalJSONFile

func UnmarshalJSONFile(location string, marshaled interface{}) error

UnmarshalJSONFile read json files and go straight to unmarshalling

Types

type AuthRequest

type AuthRequest struct {
	Email    string `json:"email" msgpack:"email"`
	Username string `json:"username" msgpack:"username"`
}

AuthRequest for unmarshalling the post body

type Branca

type Branca struct {
	Key string
	// contains filtered or unexported fields
}

Branca holds a key of exactly 32 bytes. The nonce and timestamp are used for acceptance tests.

func NewBranca

func NewBranca(key string) (b *Branca)

NewBranca creates a *Branca struct.

func (*Branca) Decode

func (b *Branca) Decode(data string) (BrancaToken, error)

Decode decode token and return payload string, expiration time.Time, and an error if any

func (*Branca) Encode

func (b *Branca) Encode(data string) (string, error)

Encode encodes the data matching the format: Version (byte) || Timestamp ([4]byte) || Nonce ([24]byte) || Ciphertext ([]byte) || Tag ([16]byte)

func (*Branca) EncodeWithTime

func (b *Branca) EncodeWithTime(data string, timeStamp time.Time) (string, error)

EncodeWithTime encodes the data matching the format: Version (byte) || Timestamp ([4]byte) || Nonce ([24]byte) || Ciphertext ([]byte) || Tag ([16]byte)

func (*Branca) SetTTL

func (b *Branca) SetTTL(ttl uint32)

SetTTL sets a Time To Live (in seconds) on the token for valid tokens.

type BrancaToken

type BrancaToken struct {
	Payload    string
	Expiration int64
	Timestamp  int64
}

BrancaToken contains all the decomposed parts of a branca token

func (*BrancaToken) ExpiresBefore

func (tk *BrancaToken) ExpiresBefore(t time.Time) bool

ExpiresBefore checks whether the token would expire before a certain time

type CodedResponse

type CodedResponse struct {
	Code    int
	Msgpack []byte
	JSON    []byte
	Msg     string
}

CodedResponse standardized way to send a prebuilt response with a status code

func MakeCodedResponse

func MakeCodedResponse(code int, msg string, primitive interface{}) *CodedResponse

MakeCodedResponse easilly generate an CodedResponse

func StaticErrorResponse

func StaticErrorResponse(code int, msg string) *CodedResponse

StaticErrorResponse generates a new error qua CodedResponse

func StaticResponse

func StaticResponse(code int, msg string) *CodedResponse

StaticResponse generates a new simple CodedResponse {msg: '...'}

func (*CodedResponse) Error

func (e *CodedResponse) Error() string

func (*CodedResponse) Send

func (e *CodedResponse) Send(c ctx) error

Send send off the error through an echo context as msgpack data with a status code

func (*CodedResponse) SendJSON

func (e *CodedResponse) SendJSON(c ctx) error

SendJSON send off the error through an echo context as json data with a status code

type Config

type Config struct {
	AppName         string `json:"appname,omitempty" toml:"appname,omitempty"`
	Domain          string `json:"domain,omitempty" toml:"domain,omitempty"`
	MaintainerEmail string `json:"maintainer_email,omitempty" toml:"maintainer_email,omitempty"`

	DevMode bool `json:"devmode,omitempty" toml:"devmode,omitempty"`

	Address                string `json:"address" toml:"address"`
	SecondaryServerAddress string `json:"secondary_server_address" toml:"secondary_server_address"`

	DevAddress                string `json:"dev_address,omitempty" toml:"dev_address,omitempty"`
	DevSecondaryServerAddress string `json:"dev_secondary_server_address,omitempty" toml:"dev_secondary_server_address,omitempty"`

	PreferMsgpack bool `json:"prefer_msgpack,omitempty" toml:"prefer_msgpack,omitempty"`

	AutoPush bool `json:"autopush,omitempty" toml:"autopush,omitempty"`

	AutoCert    bool     `json:"autocert,omitempty" toml:"autocert,omitempty"`
	DevAutoCert bool     `json:"dev_autocert,omitempty" toml:"dev_autocert,omitempty"`
	Whitelist   []string `json:"whitelist,omitempty" toml:"whitelist,omitempty"`
	Certs       string   `json:"certs,omitempty" toml:"certs,omitempty"`

	TLSKey  string `json:"tls_key,omitempty" toml:"tls_key,omitempty"`
	TLSCert string `json:"tls_cert,omitempty" toml:"tls_cert,omitempty"`

	Templates string `json:"templates,omitempty" toml:"templates,omitempty"`

	Assets           string `json:"assets,omitempty" toml:"assets,omitempty"`
	DoNotWatchAssets bool   `json:"do_not_watch_assets,omitempty" toml:"do_not_watch_assets,omitempty"`

	Private string `json:"private,omitempty" toml:"private,omitempty"`

	Cache string `json:"cache,omitempty" toml:"cache,omitempty"`

	Raw map[string]interface{} `json:"-" toml:"-"`
}

Config holds all the information necessary to fire up a mak instance

type Encoding

type Encoding struct {
	// contains filtered or unexported fields
}

Encoding is a custom base encoding defined by an alphabet. It should bre created using NewEncoding function

func NewBaseEncoding

func NewBaseEncoding(alphabet string) (*Encoding, error)

NewBaseEncoding returns a custom base encoder defined by the alphabet string. The alphabet should contain non-repeating characters. Ordering is important. Example alphabets:

  • base2: 01
  • base16: 0123456789abcdef
  • base32: 0123456789ABCDEFGHJKMNPQRSTVWXYZ
  • base62: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

func (*Encoding) Decode

func (e *Encoding) Decode(source string) ([]byte, error)

Decode function decodes a string previously obtained from Encode, using the same alphabet and returns a byte slice In case the input is not valid an arror will be returned

func (*Encoding) Encode

func (e *Encoding) Encode(source []byte) string

Encode function receives a byte slice and encodes it to a string using the alphabet provided

type LogEntry

type LogEntry struct {
	Method   string    `json:"method,omitempty"`
	Path     string    `json:"path,omitempty"`
	IP       string    `json:"client,omitempty"`
	Code     int       `json:"code,omitempty"`
	Latency  float64   `json:"latency,omitempty"`
	Start    time.Time `json:"start,omitempty"`
	End      time.Time `json:"end,omitempty"`
	BytesOut int64     `json:"bytesOut,omitempty"`
	BytesIn  int64     `json:"bytesIn,omitempty"`
	DevMode  bool      `json:"devmode,omitempty"`
	Err      string    `json:"err,omitempty"`
	Headers  obj       `json:"headers,omitempty"`
}

LogEntry is a struct containing request logging info

type PageError

type PageError struct {
	Code    int
	Path    string
	Content []byte
	Value   string
}

PageError implements error but can send an .html file as a response

var Err404NotFound *PageError

Err404NotFound is the standard 404 error response returned by Anend

func MakePageErr

func MakePageErr(code int, value, path string) *PageError

MakePageErr generates a new *PageError

func (*PageError) Error

func (pe *PageError) Error() string

func (*PageError) Send

func (pe *PageError) Send(c ctx) error

Send responds to a request with an .html error page

type Role

type Role = int64

Role auth roles/perms

const (
	// UnverifiedUser user with unconfirmed email
	UnverifiedUser Role = iota + 1
	// VerifiedUser a verified user
	VerifiedUser
	// Admin boss man with all the perms
	Admin
)

type Template

type Template struct {
	NoWatch   bool
	Templates string
	Watcher   *fsnotify.Watcher

	sync.Mutex
	// contains filtered or unexported fields
}

Template to implement echo.Renderer

var Renderer *Template

Renderer is the central app renderer

func (*Template) AsBytes

func (t *Template) AsBytes(name string, vars interface{}) ([]byte, error)

AsBytes executes a template and writes it's output to a []byte

func (*Template) Exec

func (t *Template) Exec(writer io.Writer, name string, vars interface{}) error

Exec is a surfaced method to call ExecuteTemplates on the underlying template(s)

func (*Template) Init

func (t *Template) Init() error

Init initializes the *Template (reading/parsing/watching)

func (*Template) Render

func (t *Template) Render(c ctx, code int, name string, data interface{}) error

Render a template

func (*Template) Update

func (t *Template) Update() error

Update tries to parse the templates again, and updates the Renderer accordingly

type Timeframe

type Timeframe struct {
	Start time.Time `json:"start,omitempty" msgpack:"start"`
	End   time.Time `json:"end,omitempty" msgpack:"end"`
}

Timeframe a distance of time between a .Start time and a .Finish time

type User

type User struct {
	Key         string      `json:"_key,omitempty"`
	Email       string      `json:"email"`
	EmailMD5    string      `json:"emailmd5"`
	Username    string      `json:"username"`
	Description string      `json:"description,omitempty"`
	Verifier    string      `json:"verifier,omitempty"`
	Created     time.Time   `json:"created,omitempty"`
	Logins      []time.Time `json:"logins,omitempty"`
	Sessions    []time.Time `json:"sessions,omitempty"`
	Roles       []Role      `json:"roles,omitempty"`
	Friends     []string    `json:"friends,omitempty"`
	Exp         int64       `json:"exp,omitempty"`
	Subscriber  bool        `json:"subscriber,omitempty"`
}

User struct describing a user account

func AuthenticateUser

func AuthenticateUser(email, username string) (User, error)

AuthenticateUser create and/or authenticate a user

func CredentialCheck

func CredentialCheck(c ctx) (*User, error)

CredentialCheck get an authorized user from a route handler's context

func UserByDetails

func UserByDetails(email, username string) (User, error)

UserByDetails attempt to get a user via their email/username combo

func UserByEmail

func UserByEmail(email string) (User, error)

UserByEmail get user with a certain email

func UserByKey

func UserByKey(key string) (User, error)

UserByKey retrieve user using their db document key

func UserByUsername

func UserByUsername(username string) (User, error)

UserByUsername get user with a certain username

func ValidateAuthToken

func ValidateAuthToken(token string) (User, bool)

ValidateAuthToken and return a user if ok

func VerifyUser

func VerifyUser(verifier string) (*User, error)

VerifyUser from a verifier token, check that a user has verified their email at least once

func (*User) HasRole

func (user *User) HasRole(role Role) bool

HasRole check that a user has a particular auth role

func (*User) HasRoles

func (user *User) HasRoles(roles []Role) bool

HasRoles check that a user has particular auth roles

func (*User) IsValid

func (user *User) IsValid() bool

IsValid check that the user's username and email are valid

func (*User) SetupVerifier

func (user *User) SetupVerifier() error

SetupVerifier initiate verification process with verifier and db update

func (*User) Update

func (user *User) Update(query string, vars obj) error

Update update a user's details using a common map

func (*User) Verified

func (user *User) Verified() bool

Verified check that a user has verified their email at least once

type Writ

type Writ struct {
	Key         string      `json:"_key,omitempty" msgpack:"_key,omitempty"`
	Type        string      `json:"type,omitempty" msgpack:"type,omitempty"`
	Title       string      `json:"title,omitempty" msgpack:"title,omitempty"`
	AuthorKey   string      `json:"authorkey,omitempty" msgpack:"authorkey,omitempty"`
	Author      string      `json:"author,omitempty" msgpack:"author,omitempty"`
	Content     string      `json:"content,omitempty" msgpack:"content,omitempty"`
	Injection   string      `json:"injection,omitempty" msgpack:"injection,omitempty"`
	Markdown    string      `json:"markdown,omitempty" msgpack:"markdown,omitempty"`
	Description string      `json:"description,omitempty" msgpack:"description,omitempty"`
	Slug        string      `json:"slug,omitempty" msgpack:"slug,omitempty"`
	Tags        []string    `json:"tags,omitempty" msgpack:"tags,omitempty"`
	Edits       []time.Time `json:"edits,omitempty" msgpack:"edits,omitempty"`
	Created     time.Time   `json:"created,omitempty" msgpack:"created,omitempty"`
	Views       int64       `json:"views,omitempty" msgpack:"views,omitempty"`
	ViewedBy    []string    `json:"viewedby,omitempty" msgpack:"viewedby,omitempty"`
	LikedBy     []string    `json:"likedby,omitempty" msgpack:"likedby,omitempty"`
	Public      bool        `json:"public,omitempty" msgpack:"public,omitempty"`
	MembersOnly bool        `json:"membersonly,omitempty" msgpack:"membersonly,omitempty"`
	NoComments  bool        `json:"nocomments,omitempty" msgpack:"nocomments,omitempty"`
	Roles       []int64     `json:"roles,omitempty" msgpack:"roles,omitempty"`
}

Writ - struct representing a post or document in the database

func WritByKey

func WritByKey(key string) (Writ, error)

WritByKey retrieve user using their db document key

func (w *Writ) GetLink() string

GetLink get a slug link with a key query param incase the title/slug changed

func (*Writ) RenderContent

func (w *Writ) RenderContent()

RenderContent from .Markdown generate html and set .Content

func (*Writ) Slugify

func (w *Writ) Slugify()

Slugify generate and set .Slug from .Title

func (*Writ) ToObj

func (w *Writ) ToObj(omissions ...string) obj

ToObj convert writ into map[string]interface{}

func (*Writ) Update

func (w *Writ) Update(query string, vars obj) error

Update update a writ's details using a map[string]interface{}

type WritQuery

type WritQuery struct {
	One                bool                   `json:"one,omitempty" msgpack:"one,omitempty"`
	Key                string                 `json:"_key,omitempty" msgpack:"_key,omitempty"`
	PrivateOnly        bool                   `json:"privateonly,omitempty" msgpack:"privateonly,omitempty"`
	IncludePrivate     bool                   `json:"includeprivate,omitempty" msgpack:"includeprivate,omitempty"`
	EditorMode         bool                   `json:"editormode,omitempty" msgpack:"editormode,omitempty"`
	Extensive          bool                   `json:"extensive,omitempty" msgpack:"extensive,omitempty"`
	UpdateViews        bool                   `json:"updateviews,omitempty" msgpack:"updateviews,omitempty"`
	Comments           bool                   `json:"comments,omitempty" msgpack:"comments,omitempty"`
	MembersOnly        bool                   `json:"membersonly,omitempty" msgpack:"membersonly,omitempty"`
	IncludeMembersOnly bool                   `json:"includemembersonly,omitempty" msgpack:"includemembersonly,omitempty"`
	DontSort           bool                   `json:"dontsort,omitempty" msgpack:"dontsort,omitempty"`
	Vars               map[string]interface{} `json:"vars,omitempty" msgpack:"vars,omitempty"`
	ViewedBy           string                 `json:"viewedby,omitempty" msgpack:"viewedby,omitempty"`
	LikedBy            string                 `json:"likedby,omitempty" msgpack:"likedby,omitempty"`
	Viewer             string                 `json:"viewer,omitempty" msgpack:"viewer,omitempty"`
	Title              string                 `json:"title,omitempty" msgpack:"title,omitempty"`
	Slug               string                 `json:"slug,omitempty" msgpack:"slug,omitempty"`
	Author             string                 `json:"author,omitempty" msgpack:"author,omitempty"`
	Created            time.Time              `json:"created,omitempty" msgpack:"created,omitempty"`
	Between            Timeframe              `json:"between,omitempty" msgpack:"between,omitempty"`
	Roles              []int64                `json:"roles,omitempty" msgpack:"roles,omitempty"`
	Limit              []int64                `json:"limit,omitempty" msgpack:"limit,omitempty"`
	Tags               []string               `json:"tags,omitempty" msgpack:"tags,omitempty"`
	Omissions          []string               `json:"omissions,omitempty" msgpack:"omissions,omitempty"`
}

WritQuery a easier way to query the db for writs

func (*WritQuery) Exec

func (q *WritQuery) Exec() ([]Writ, error)

Exec execute a WritQuery to retrieve some/certain writs

func (*WritQuery) ExecOne

func (q *WritQuery) ExecOne() (Writ, error)

ExecOne execute a WritQuery to retrieve a single writ

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL