wip
This commit is contained in:
		
							
								
								
									
										3
									
								
								hub/api/db/generate.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								hub/api/db/generate.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| package db | ||||
|  | ||||
| //go:generate sqlgen sqlite tables.defs generated.go | ||||
							
								
								
									
										0
									
								
								hub/api/db/generated
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								hub/api/db/generated
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										480
									
								
								hub/api/db/generated.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										480
									
								
								hub/api/db/generated.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,480 @@ | ||||
| package db | ||||
|  | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"iter" | ||||
| ) | ||||
|  | ||||
| type TX interface { | ||||
| 	Exec(query string, args ...any) (sql.Result, error) | ||||
| 	Query(query string, args ...any) (*sql.Rows, error) | ||||
| 	QueryRow(query string, args ...any) *sql.Row | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Table: config | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| type Config struct { | ||||
| 	ConfigID   int64 | ||||
| 	HubAddress string | ||||
| 	VPNNetwork []byte | ||||
| 	Password   []byte | ||||
| } | ||||
|  | ||||
| const Config_SelectQuery = "SELECT ConfigID,HubAddress,VPNNetwork,Password FROM config" | ||||
|  | ||||
| func Config_Insert( | ||||
| 	tx TX, | ||||
| 	row *Config, | ||||
| ) (err error) { | ||||
| 	Config_Sanitize(row) | ||||
| 	if err = Config_Validate(row); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = tx.Exec("INSERT INTO config(ConfigID,HubAddress,VPNNetwork,Password) VALUES(?,?,?,?)", row.ConfigID, row.HubAddress, row.VPNNetwork, row.Password) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Config_Update( | ||||
| 	tx TX, | ||||
| 	row *Config, | ||||
| ) (err error) { | ||||
| 	Config_Sanitize(row) | ||||
| 	if err = Config_Validate(row); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result, err := tx.Exec("UPDATE config SET HubAddress=?,VPNNetwork=? WHERE ConfigID=?", row.HubAddress, row.VPNNetwork, row.ConfigID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n, err := result.RowsAffected() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	switch n { | ||||
| 	case 0: | ||||
| 		return sql.ErrNoRows | ||||
| 	case 1: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		panic("multiple rows updated") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Config_UpdateFull( | ||||
| 	tx TX, | ||||
| 	row *Config, | ||||
| ) (err error) { | ||||
| 	Config_Sanitize(row) | ||||
| 	if err = Config_Validate(row); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result, err := tx.Exec("UPDATE config SET HubAddress=?,VPNNetwork=?,Password=? WHERE ConfigID=?", row.HubAddress, row.VPNNetwork, row.Password, row.ConfigID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n, err := result.RowsAffected() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	switch n { | ||||
| 	case 0: | ||||
| 		return sql.ErrNoRows | ||||
| 	case 1: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		panic("multiple rows updated") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Config_Delete( | ||||
| 	tx TX, | ||||
| 	ConfigID int64, | ||||
| ) (err error) { | ||||
| 	result, err := tx.Exec("DELETE FROM config WHERE ConfigID=?", ConfigID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n, err := result.RowsAffected() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	switch n { | ||||
| 	case 0: | ||||
| 		return sql.ErrNoRows | ||||
| 	case 1: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		panic("multiple rows deleted") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Config_Get( | ||||
| 	tx TX, | ||||
| 	ConfigID int64, | ||||
| ) ( | ||||
| 	row *Config, | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Config{} | ||||
| 	r := tx.QueryRow("SELECT ConfigID,HubAddress,VPNNetwork,Password FROM config WHERE ConfigID=?", ConfigID) | ||||
| 	err = r.Scan(&row.ConfigID, &row.HubAddress, &row.VPNNetwork, &row.Password) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Config_GetWhere( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) ( | ||||
| 	row *Config, | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Config{} | ||||
| 	r := tx.QueryRow(query, args...) | ||||
| 	err = r.Scan(&row.ConfigID, &row.HubAddress, &row.VPNNetwork, &row.Password) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Config_Iterate( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) iter.Seq2[*Config, error] { | ||||
| 	rows, err := tx.Query(query, args...) | ||||
| 	if err != nil { | ||||
| 		return func(yield func(*Config, error) bool) { | ||||
| 			yield(nil, err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return func(yield func(*Config, error) bool) { | ||||
| 		defer rows.Close() | ||||
| 		for rows.Next() { | ||||
| 			row := &Config{} | ||||
| 			err := rows.Scan(&row.ConfigID, &row.HubAddress, &row.VPNNetwork, &row.Password) | ||||
| 			if !yield(row, err) { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Config_List( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) ( | ||||
| 	l []*Config, | ||||
| 	err error, | ||||
| ) { | ||||
| 	for row, err := range Config_Iterate(tx, query, args...) { | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		l = append(l, row) | ||||
| 	} | ||||
| 	return l, nil | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Table: sessions | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| type Session struct { | ||||
| 	SessionID  string | ||||
| 	CSRF       string | ||||
| 	SignedIn   bool | ||||
| 	CreatedAt  int64 | ||||
| 	LastSeenAt int64 | ||||
| } | ||||
|  | ||||
| const Session_SelectQuery = "SELECT SessionID,CSRF,SignedIn,CreatedAt,LastSeenAt FROM sessions" | ||||
|  | ||||
| func Session_Insert( | ||||
| 	tx TX, | ||||
| 	row *Session, | ||||
| ) (err error) { | ||||
| 	Session_Sanitize(row) | ||||
| 	if err = Session_Validate(row); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = tx.Exec("INSERT INTO sessions(SessionID,CSRF,SignedIn,CreatedAt,LastSeenAt) VALUES(?,?,?,?,?)", row.SessionID, row.CSRF, row.SignedIn, row.CreatedAt, row.LastSeenAt) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Session_Delete( | ||||
| 	tx TX, | ||||
| 	SessionID string, | ||||
| ) (err error) { | ||||
| 	result, err := tx.Exec("DELETE FROM sessions WHERE SessionID=?", SessionID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n, err := result.RowsAffected() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	switch n { | ||||
| 	case 0: | ||||
| 		return sql.ErrNoRows | ||||
| 	case 1: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		panic("multiple rows deleted") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Session_Get( | ||||
| 	tx TX, | ||||
| 	SessionID string, | ||||
| ) ( | ||||
| 	row *Session, | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Session{} | ||||
| 	r := tx.QueryRow("SELECT SessionID,CSRF,SignedIn,CreatedAt,LastSeenAt FROM sessions WHERE SessionID=?", SessionID) | ||||
| 	err = r.Scan(&row.SessionID, &row.CSRF, &row.SignedIn, &row.CreatedAt, &row.LastSeenAt) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Session_GetWhere( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) ( | ||||
| 	row *Session, | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Session{} | ||||
| 	r := tx.QueryRow(query, args...) | ||||
| 	err = r.Scan(&row.SessionID, &row.CSRF, &row.SignedIn, &row.CreatedAt, &row.LastSeenAt) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Session_Iterate( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) iter.Seq2[*Session, error] { | ||||
| 	rows, err := tx.Query(query, args...) | ||||
| 	if err != nil { | ||||
| 		return func(yield func(*Session, error) bool) { | ||||
| 			yield(nil, err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return func(yield func(*Session, error) bool) { | ||||
| 		defer rows.Close() | ||||
| 		for rows.Next() { | ||||
| 			row := &Session{} | ||||
| 			err := rows.Scan(&row.SessionID, &row.CSRF, &row.SignedIn, &row.CreatedAt, &row.LastSeenAt) | ||||
| 			if !yield(row, err) { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Session_List( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) ( | ||||
| 	l []*Session, | ||||
| 	err error, | ||||
| ) { | ||||
| 	for row, err := range Session_Iterate(tx, query, args...) { | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		l = append(l, row) | ||||
| 	} | ||||
| 	return l, nil | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Table: peers | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| type Peer struct { | ||||
| 	PeerIP     byte | ||||
| 	APIKey     string | ||||
| 	Name       string | ||||
| 	IP         []byte | ||||
| 	Port       uint16 | ||||
| 	Mediator   bool | ||||
| 	EncPubKey  []byte | ||||
| 	SignPubKey []byte | ||||
| } | ||||
|  | ||||
| const Peer_SelectQuery = "SELECT PeerIP,APIKey,Name,IP,Port,Mediator,EncPubKey,SignPubKey FROM peers" | ||||
|  | ||||
| func Peer_Insert( | ||||
| 	tx TX, | ||||
| 	row *Peer, | ||||
| ) (err error) { | ||||
| 	Peer_Sanitize(row) | ||||
| 	if err = Peer_Validate(row); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = tx.Exec("INSERT INTO peers(PeerIP,APIKey,Name,IP,Port,Mediator,EncPubKey,SignPubKey) VALUES(?,?,?,?,?,?,?,?)", row.PeerIP, row.APIKey, row.Name, row.IP, row.Port, row.Mediator, row.EncPubKey, row.SignPubKey) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Peer_Update( | ||||
| 	tx TX, | ||||
| 	row *Peer, | ||||
| ) (err error) { | ||||
| 	Peer_Sanitize(row) | ||||
| 	if err = Peer_Validate(row); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result, err := tx.Exec("UPDATE peers SET Name=?,IP=?,Port=?,Mediator=? WHERE PeerIP=?", row.Name, row.IP, row.Port, row.Mediator, row.PeerIP) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n, err := result.RowsAffected() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	switch n { | ||||
| 	case 0: | ||||
| 		return sql.ErrNoRows | ||||
| 	case 1: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		panic("multiple rows updated") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Peer_UpdateFull( | ||||
| 	tx TX, | ||||
| 	row *Peer, | ||||
| ) (err error) { | ||||
| 	Peer_Sanitize(row) | ||||
| 	if err = Peer_Validate(row); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result, err := tx.Exec("UPDATE peers SET APIKey=?,Name=?,IP=?,Port=?,Mediator=?,EncPubKey=?,SignPubKey=? WHERE PeerIP=?", row.APIKey, row.Name, row.IP, row.Port, row.Mediator, row.EncPubKey, row.SignPubKey, row.PeerIP) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n, err := result.RowsAffected() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	switch n { | ||||
| 	case 0: | ||||
| 		return sql.ErrNoRows | ||||
| 	case 1: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		panic("multiple rows updated") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Peer_Delete( | ||||
| 	tx TX, | ||||
| 	PeerIP byte, | ||||
| ) (err error) { | ||||
| 	result, err := tx.Exec("DELETE FROM peers WHERE PeerIP=?", PeerIP) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n, err := result.RowsAffected() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	switch n { | ||||
| 	case 0: | ||||
| 		return sql.ErrNoRows | ||||
| 	case 1: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		panic("multiple rows deleted") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Peer_Get( | ||||
| 	tx TX, | ||||
| 	PeerIP byte, | ||||
| ) ( | ||||
| 	row *Peer, | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Peer{} | ||||
| 	r := tx.QueryRow("SELECT PeerIP,APIKey,Name,IP,Port,Mediator,EncPubKey,SignPubKey FROM peers WHERE PeerIP=?", PeerIP) | ||||
| 	err = r.Scan(&row.PeerIP, &row.APIKey, &row.Name, &row.IP, &row.Port, &row.Mediator, &row.EncPubKey, &row.SignPubKey) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Peer_GetWhere( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) ( | ||||
| 	row *Peer, | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Peer{} | ||||
| 	r := tx.QueryRow(query, args...) | ||||
| 	err = r.Scan(&row.PeerIP, &row.APIKey, &row.Name, &row.IP, &row.Port, &row.Mediator, &row.EncPubKey, &row.SignPubKey) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Peer_Iterate( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) iter.Seq2[*Peer, error] { | ||||
| 	rows, err := tx.Query(query, args...) | ||||
| 	if err != nil { | ||||
| 		return func(yield func(*Peer, error) bool) { | ||||
| 			yield(nil, err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return func(yield func(*Peer, error) bool) { | ||||
| 		defer rows.Close() | ||||
| 		for rows.Next() { | ||||
| 			row := &Peer{} | ||||
| 			err := rows.Scan(&row.PeerIP, &row.APIKey, &row.Name, &row.IP, &row.Port, &row.Mediator, &row.EncPubKey, &row.SignPubKey) | ||||
| 			if !yield(row, err) { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Peer_List( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) ( | ||||
| 	l []*Peer, | ||||
| 	err error, | ||||
| ) { | ||||
| 	for row, err := range Peer_Iterate(tx, query, args...) { | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		l = append(l, row) | ||||
| 	} | ||||
| 	return l, nil | ||||
| } | ||||
							
								
								
									
										69
									
								
								hub/api/db/sanitize-validate.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								hub/api/db/sanitize-validate.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| package db | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"net/netip" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	ErrInvalidIP   = errors.New("invalid IP") | ||||
| 	ErrInvalidPort = errors.New("invalid port") | ||||
| ) | ||||
|  | ||||
| func Config_Sanitize(c *Config) { | ||||
| 	if u, err := url.Parse(c.HubAddress); err == nil { | ||||
| 		c.HubAddress = u.String() | ||||
| 	} | ||||
|  | ||||
| 	if addr, ok := netip.AddrFromSlice(c.VPNNetwork); ok { | ||||
| 		c.VPNNetwork = addr.AsSlice() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Config_Validate(c *Config) error { | ||||
| 	if _, err := url.Parse(c.HubAddress); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	addr, ok := netip.AddrFromSlice(c.VPNNetwork) | ||||
| 	if !ok || !addr.Is4() || addr.As4()[3] != 0 || addr.As4()[0] == 0 { | ||||
| 		return ErrInvalidIP | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func Session_Sanitize(s *Session) { | ||||
| } | ||||
|  | ||||
| func Session_Validate(s *Session) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func Peer_Sanitize(p *Peer) { | ||||
| 	p.Name = strings.TrimSpace(p.Name) | ||||
| 	if len(p.IP) != 0 { | ||||
| 		addr, ok := netip.AddrFromSlice(p.IP) | ||||
| 		if ok && addr.Is4() { | ||||
| 			p.IP = addr.AsSlice() | ||||
| 		} | ||||
| 	} | ||||
| 	if p.Port == 0 { | ||||
| 		p.Port = 515 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Peer_Validate(p *Peer) error { | ||||
| 	if len(p.IP) > 0 { | ||||
| 		_, ok := netip.AddrFromSlice(p.IP) | ||||
| 		if !ok { | ||||
| 			return ErrInvalidIP | ||||
| 		} | ||||
| 	} | ||||
| 	if p.Port == 0 { | ||||
| 		return ErrInvalidPort | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										25
									
								
								hub/api/db/tables.defs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								hub/api/db/tables.defs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| TABLE config OF Config ( | ||||
|   ConfigID    int64  PK, | ||||
|   HubAddress  string, | ||||
|   VPNNetwork  []byte, | ||||
|   Password    []byte NoUpdate | ||||
| ); | ||||
|  | ||||
| TABLE sessions OF Session NoUpdate ( | ||||
|   SessionID  string PK, | ||||
|   CSRF       string, | ||||
|   SignedIn   bool, | ||||
|   CreatedAt  int64, | ||||
|   LastSeenAt int64 | ||||
| ); | ||||
|  | ||||
| TABLE peers OF Peer ( | ||||
|   PeerIP     byte PK, | ||||
|   APIKey     string NoUpdate, | ||||
|   Name       string, | ||||
|   IP         []byte, | ||||
|   Port       uint16, | ||||
|   Mediator   bool, | ||||
|   EncPubKey  []byte NoUpdate, | ||||
|   SignPubKey []byte NoUpdate | ||||
| ); | ||||
							
								
								
									
										51
									
								
								hub/api/db/written.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								hub/api/db/written.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| package db | ||||
|  | ||||
| import "vppn/fasttime" | ||||
|  | ||||
| func Session_UpdateLastSeenAt( | ||||
| 	tx TX, | ||||
| 	id string, | ||||
| ) (err error) { | ||||
| 	_, err = tx.Exec("UPDATE sessions SET LastSeenAt=? WHERE SessionID=?", fasttime.Now(), id) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Session_SetSignedIn( | ||||
| 	tx TX, | ||||
| 	id string, | ||||
| ) (err error) { | ||||
| 	_, err = tx.Exec("UPDATE sessions SET SignedIn=1 WHERE SessionID=?", id) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Session_DeleteBefore( | ||||
| 	tx TX, | ||||
| 	timestamp int64, | ||||
| ) (err error) { | ||||
| 	_, err = tx.Exec("DELETE FROM sessions WHERE LastSeenAt<?", timestamp) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Config_UpdatePassword( | ||||
| 	tx TX, | ||||
| 	pwdHash []byte, | ||||
| ) (err error) { | ||||
| 	_, err = tx.Exec("UPDATE config SET Password=? WHERE ConfigID=1", pwdHash) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Peer_ListAll(tx TX) ([]*Peer, error) { | ||||
| 	return Peer_List(tx, Peer_SelectQuery) | ||||
| } | ||||
|  | ||||
| func Peer_GetByAPIKey(tx TX, apiKey string) (*Peer, error) { | ||||
| 	return Peer_GetWhere( | ||||
| 		tx, | ||||
| 		Peer_SelectQuery+` WHERE APIKey=?`, | ||||
| 		apiKey) | ||||
| } | ||||
|  | ||||
| func Peer_Exists(tx TX, ip byte) (exists bool, err error) { | ||||
| 	err = tx.QueryRow(`SELECT EXISTS(SELECT 1 FROM peers WHERE PeerIP=?)`, ip).Scan(&exists) | ||||
| 	return | ||||
| } | ||||
		Reference in New Issue
	
	Block a user