|
- // NGnius 2020-02-12
-
- package main
-
- import (
- "crypto/rand"
- "crypto/sha512"
- "encoding/binary"
- "encoding/json"
- "math/big"
- "strconv"
- // test
- //"fmt"
- )
-
- var (
- randomizeTokens bool
- )
-
- type Jsonable interface {
- Json() ([]byte, error)
- JsonPretty() ([]byte, error)
- Unjson([]byte) error
- JsonObject() (interface{}, error)
- }
-
- type Rower interface {
- Intake() []interface{}
- Output() []interface{}
- }
-
- type Board struct {
- ID int64
- Name string
- Description string
- }
-
- func LoadBoard(id int64) *Board {
- b := &Board{ID: id}
- loadErr := b.Load()
- if loadErr != nil {
- return nil
- }
- return b
- }
-
- func (b *Board) Load() error {
- return db.QueryRow(queryStrings[queryType][7], b.ID).Scan(b.Intake()...)
- }
-
- func (b *Board) Commit() error {
- tx, _ := db.Begin()
- statement, _ := tx.Prepare(queryStrings[queryType][8])
- _, err := statement.Exec(b.Output()...)
- if err != nil {
- tx.Rollback()
- return err
- }
- return tx.Commit()
- }
-
- func (b *Board) Entries() ([]*Entry, error) {
- var entries []*Entry
- rows, err := db.Query(queryStrings[queryType][9], b.ID)
- if err != nil {
- return entries, err
- }
- count := 0
- for rows.Next() {
- entries = append(entries, &Entry{})
- scanErr := rows.Scan(entries[count].Intake()...)
- if scanErr != nil {
- return entries, scanErr
- }
- count++
- }
- return entries, nil
- }
-
- func (b *Board) SomeEntries(start, end int64) ([]*Entry, error) {
- var entries []*Entry
- rows, err := db.Query(queryStrings[queryType][10], b.ID, start, end)
- if err != nil {
- return entries, err
- }
- count := 0
- for rows.Next() {
- entries = append(entries, &Entry{})
- scanErr := rows.Scan(entries[count].Intake()...)
- if scanErr != nil {
- return entries, scanErr
- }
- count++
- }
- return entries, nil
- }
-
- func (b *Board) Url() string {
- return "/board?name=" + b.Name
- }
-
- // implementation of Jsonable
- func (b *Board) Json() ([]byte, error) {
- var data []byte
- jsonObj, err := b.JsonObject()
- if err != nil {
- return data, err
- }
- return json.Marshal(jsonObj)
- }
-
- func (b *Board) JsonPretty() ([]byte, error) {
- var data []byte
- jsonObj, err := b.JsonObject()
- if err != nil {
- return data, err
- }
- return json.MarshalIndent(jsonObj, "", " ")
- }
-
- func (b *Board) JsonObject() (interface{}, error) {
- jsonObj := BoardJSON{ID: b.ID, Name: b.Name, Description: b.Description, Url: b.Url()}
- return jsonObj, nil
- }
-
- // implementation of Rower
- func (b *Board) Intake() []interface{} {
- return []interface{}{&b.ID, &b.Name, &b.Description}
- }
-
- func (b *Board) Output() []interface{} {
- return []interface{}{b.ID, b.Name, b.Description}
- }
-
- type Player struct {
- ID int64
- Name string
- }
-
- func LoadPlayer(id int64) *Player {
- p := &Player{ID: id}
- loadErr := p.Load()
- if loadErr != nil {
- return nil
- }
- return p
- }
-
- func (p *Player) Load() error {
- return db.QueryRow(queryStrings[queryType][11], p.ID).Scan(p.Intake()...)
- }
-
- func (p *Player) Commit() error {
- tx, _ := db.Begin()
- statement, _ := tx.Prepare(queryStrings[queryType][12])
- _, err := statement.Exec(p.Output()...)
- if err != nil {
- tx.Rollback()
- return err
- }
- return tx.Commit()
- }
-
- func (p *Player) Entries() ([]*Entry, error) {
- var entries []*Entry
- rows, err := db.Query(queryStrings[queryType][13], p.ID)
- if err != nil {
- return entries, err
- }
- count := 0
- for rows.Next() {
- entries = append(entries, &Entry{})
- scanErr := rows.Scan(entries[count].Intake()...)
- if scanErr != nil {
- return entries, scanErr
- }
- count++
- }
- return entries, nil
- }
-
- func (p *Player) SomeEntries(limit int64) ([]*Entry, error) {
- var entries []*Entry
- rows, err := db.Query(queryStrings[queryType][14], p.ID, limit)
- if err != nil {
- return entries, err
- }
- count := 0
- for rows.Next() {
- entries = append(entries, &Entry{})
- scanErr := rows.Scan(entries[count].Intake()...)
- if scanErr != nil {
- return entries, scanErr
- }
- count++
- }
- return entries, nil
- }
-
- func (p *Player) Url() string {
- return "/player?id=" + strconv.Itoa(int(p.ID))
- }
-
- // implementation of Jsonable
- func (p *Player) Json() ([]byte, error) {
- var data []byte
- jsonObj, err := p.JsonObject()
- if err != nil {
- return data, err
- }
- return json.Marshal(jsonObj)
- }
-
- func (p *Player) JsonPretty() ([]byte, error) {
- var data []byte
- jsonObj, err := p.JsonObject()
- if err != nil {
- return data, err
- }
- return json.MarshalIndent(jsonObj, "", " ")
- }
-
- func (p *Player) JsonObject() (interface{}, error) {
- jsonObj := PlayerJSON{ID: p.ID, Name: p.Name, Url: p.Url()}
- return jsonObj, nil
- }
-
- // implementation of Rower
- func (p *Player) Intake() []interface{} {
- return []interface{}{&p.ID, &p.Name}
- }
-
- func (p *Player) Output() []interface{} {
- return []interface{}{p.ID, p.Name}
- }
-
- type Entry struct {
- ID int64
- Rank int64
- Score int64
- Player int64
- Board int64
- Time int64 // Created time (seconds since Unix epoch)
- Metadata []byte
- }
-
- func LoadEntry(id int64) *Entry {
- e := &Entry{ID: id}
- loadErr := e.Load()
- if loadErr != nil {
- return nil
- }
- return e
- }
-
- func (e *Entry) Load() error {
- return db.QueryRow(queryStrings[queryType][15], e.ID).Scan(e.Intake()...)
- }
-
- func (e *Entry) Commit() error {
- tx, _ := db.Begin()
- statement, _ := tx.Prepare(queryStrings[queryType][16])
- _, err := statement.Exec(e.Output()...)
- if err != nil {
- tx.Rollback()
- return err
- }
- return tx.Commit()
- }
-
- // implementation of Jsonable
- func (e *Entry) Json() ([]byte, error) {
- var data []byte
- jsonObj, err := e.JsonObject()
- if err != nil {
- return data, err
- }
- return json.Marshal(jsonObj)
- }
-
- func (e *Entry) JsonPretty() ([]byte, error) {
- var data []byte
- jsonObj, err := e.JsonObject()
- if err != nil {
- return data, err
- }
- return json.MarshalIndent(jsonObj, "", " ")
- }
-
- func (e *Entry) JsonObject() (interface{}, error) {
- jsonObj := EntryJSON{ID: e.ID, Rank: e.Rank, Score: e.Score, PlayerID: e.Player, BoardID: e.Board}
- ePlayer := &Player{ID: e.Player}
- err := ePlayer.Load()
- if err != nil {
- return jsonObj, err
- }
- jsonObj.PlayerName = ePlayer.Name
- jsonObj.PlayerURL = ePlayer.Url()
- eBoard := &Board{ID: e.Board}
- err = eBoard.Load()
- if err != nil {
- return jsonObj, err
- }
- jsonObj.BoardName = eBoard.Name
- jsonObj.BoardURL = eBoard.Url()
- return jsonObj, nil
- }
-
- // implementation of Rower
- func (e *Entry) Intake() []interface{} {
- return []interface{}{&e.ID, &e.Rank, &e.Score, &e.Player, &e.Board, &e.Time, &e.Metadata}
- }
-
- func (e *Entry) Output() []interface{} {
- return []interface{}{e.ID, e.Rank, e.Score, e.Player, e.Board, e.Time, e.Metadata}
- }
-
- type Key struct {
- ID int64
- Token string
- Player int64
- Time int64 // Created time (seconds since Unix epoch)
- Metadata []byte
- }
-
- func LoadKey(id int64) *Key {
- k := &Key{ID: id}
- loadErr := k.Load()
- if loadErr != nil {
- return nil
- }
- return k
- }
-
- func (k *Key) Load() error {
- return db.QueryRow(queryStrings[queryType][17], k.ID).Scan(k.Intake()...)
- }
-
- func (k *Key) Commit() error {
- tx, _ := db.Begin()
- statement, _ := tx.Prepare(queryStrings[queryType][18])
- _, err := statement.Exec(k.Output()...)
- if err != nil {
- tx.Rollback()
- return err
- }
- return tx.Commit()
- }
-
- func (k *Key) IsEnabled() bool {
- return (k.Metadata[0] & 0b00000001) == 0
- }
-
- func (k *Key) Disable() {
- k.Metadata[0] = k.Metadata[0] | 0b00000001
- }
-
- func (k *Key) IsSuperuser() bool {
- return (k.Metadata[0] & 0b00000100) == 0
- }
-
- func (k *Key) Promote() {
- k.Metadata[0] = k.Metadata[0] | 0b00000100
- }
-
- func (k *Key) IsMultiuser() bool {
- return (k.Metadata[0] & 0b00010000) == 0
- }
-
- func (k *Key) Develop() {
- k.Metadata[0] = k.Metadata[0] | 0b00010000
- }
-
- func (k *Key) GenerateToken() error {
- buf_int64 := make([]byte, 10) // 8 bytes = 64 bits
- input := []byte{}
- if randomizeTokens {
- max := big.NewInt(2 ^ 16 - 1)
- for i := 0; i < 512; i++ {
- // generate randomness
- num, _ := rand.Int(rand.Reader, max)
- input = append(input, num.Bytes()...)
- }
- }
- binary.PutVarint(buf_int64, k.ID)
- input = append(input, buf_int64[0:8]...)
- binary.PutVarint(buf_int64, k.Player)
- input = append(input, buf_int64[0:8]...)
- binary.PutVarint(buf_int64, k.Time)
- input = append(input, buf_int64[0:8]...)
- bToken := sha512.Sum512(input)
- //k.Token = string(bToken)
- k.Token = ""
- for _, b := range bToken {
- tmp_b := b & 0b01111111 // Valid 7-bit ASCII values only
- for !((tmp_b > 47 && tmp_b < 58) || (tmp_b > 64 && tmp_b < 91) || (tmp_b > 96 && tmp_b < 123)) {
- tmp_b = sha512.Sum512([]byte{tmp_b})[1]
- tmp_b = tmp_b & 0b01111111
- }
- k.Token += string(tmp_b)
- }
- return nil
- }
-
- // Implementation of Jsonable
- func (k *Key) Json() ([]byte, error) {
- var data []byte
- jsonObj, err := k.JsonObject()
- if err != nil {
- return data, err
- }
- return json.Marshal(jsonObj)
- }
-
- func (k *Key) JsonPretty() ([]byte, error) {
- var data []byte
- jsonObj, err := k.JsonObject()
- if err != nil {
- return data, err
- }
- return json.MarshalIndent(jsonObj, "", " ")
- }
-
- func (k *Key) JsonObject() (interface{}, error) {
- jsonObj := KeyJSON{Token: k.Token, PlayerID: k.Player}
- return jsonObj, nil
- }
-
- // Implementation of Rower
- func (k *Key) Intake() []interface{} {
- return []interface{}{&k.ID, &k.Token, &k.Player, &k.Time, &k.Metadata}
- }
-
- func (k *Key) Output() []interface{} {
- return []interface{}{k.ID, k.Token, k.Player, k.Time, k.Metadata}
- }
|