update: better CSS border colors
This commit is contained in:
parent
b24a970962
commit
4641faefc2
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
|
docker-compose.yml
|
||||||
|
compose.yml
|
||||||
security
|
security
|
||||||
db/
|
db/
|
||||||
|
9
Makefile
Normal file
9
Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
all: security
|
||||||
|
|
||||||
|
security: */*.go *.go
|
||||||
|
go build -o $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
gofmt -s -w .
|
||||||
|
|
||||||
|
.PHONY: format
|
22
README.md
22
README.md
@ -1,12 +1,26 @@
|
|||||||
# security | MatterLinux Security Tracker
|
# security | MatterLinux security tracker
|
||||||
Soruce code of MatterLinux's security tracker, located at
|
Soruce code of MatterLinux's security tracker, located at
|
||||||
[security.matterlinux.xyz](https://security.matterlinux.xyz)
|
[security.matterlinux.xyz](https://security.matterlinux.xyz)
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
Web server can be built and deployed with docker:
|
Web server can be built and deployed with docker compose, here is an
|
||||||
|
example configuration:
|
||||||
|
```yaml
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
security:
|
||||||
|
image: mattersecurity
|
||||||
|
restart: unless-stopped
|
||||||
|
build:
|
||||||
|
context: ./
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:9876:9876"
|
||||||
|
volumes:
|
||||||
|
- "./db:/app/db"
|
||||||
|
```
|
||||||
|
After saving the configuration file, you can build and run the docker container:
|
||||||
```bash
|
```bash
|
||||||
docker build --tag mattersecurity .
|
|
||||||
mkdir -pv db
|
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
12
compose.yml
12
compose.yml
@ -1,12 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
security:
|
|
||||||
image: mattersecurity
|
|
||||||
restart: unless-stopped
|
|
||||||
build:
|
|
||||||
context: ./
|
|
||||||
ports:
|
|
||||||
- "127.0.0.1:9876:9876"
|
|
||||||
volumes:
|
|
||||||
- "./db:/app/db"
|
|
50
lib/db.go
50
lib/db.go
@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Db *sql.DB
|
var Db *sql.DB
|
||||||
@ -35,34 +35,32 @@ const create_vulns string = `
|
|||||||
`
|
`
|
||||||
|
|
||||||
func LoadDatabase() error {
|
func LoadDatabase() error {
|
||||||
_, err := os.Stat("db")
|
_, err := os.Stat("db")
|
||||||
if err != nil && os.IsNotExist(err) {
|
if err != nil && os.IsNotExist(err) {
|
||||||
err = os.Mkdir("db", os.ModePerm)
|
err = os.Mkdir("db", os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
return fmt.Errorf("cannot access to db directory")
|
return fmt.Errorf("cannot access to db directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
Db, err = sql.Open("sqlite3", "db/data.db")
|
Db, err = sql.Open("sqlite3", "db/data.db")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = Db.Exec(create_users)
|
_, err = Db.Exec(create_users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = Db.Exec(create_vulns)
|
_, err = Db.Exec(create_vulns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
33
lib/lib/config.go
Normal file
33
lib/lib/config.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Pools []Pool `json:"pools"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) Load(list *[]Package, file string) error {
|
||||||
|
var (
|
||||||
|
content []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if content, err = os.ReadFile(file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(content, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range c.Pools {
|
||||||
|
if err = p.Load(list); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
135
lib/lib/package.go
Normal file
135
lib/lib/package.go
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"bufio"
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.matterlinux.xyz/matter/tracker/log"
|
||||||
|
"github.com/bigkevmcd/go-configparser"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Package struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Pool *Pool `json:"-"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Depends []string `json:"depends"`
|
||||||
|
Size string `json:"size"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
Archive string `json:"archive"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Package) Files() []string {
|
||||||
|
var (
|
||||||
|
gzip_reader io.Reader
|
||||||
|
header *tar.Header
|
||||||
|
result []string
|
||||||
|
file *os.File
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if file, err = os.Open(p.Archive); err != nil {
|
||||||
|
log.Error("Failed to open %s", p.Archive)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if gzip_reader, err = gzip.NewReader(bufio.NewReader(file)); err != nil {
|
||||||
|
log.Error("Failed to create reader for %s", p.Archive)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := tar.NewReader(gzip_reader)
|
||||||
|
|
||||||
|
for header, err = reader.Next(); err == nil; header, err = reader.Next() {
|
||||||
|
if header.Typeflag != tar.TypeReg {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.Base(header.Name) != "files.tar.gz" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if result, err = GetFiles(reader); err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Error("Failed to get file list for %s: %s", p.Archive, err.Error())
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Package) URL() string {
|
||||||
|
if nil == p.Pool {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
url, _ := url.JoinPath(p.Pool.Source, "src/branch/"+p.Pool.Branch+"/src", p.Name)
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Package) DependsToStr() string {
|
||||||
|
var depends string = ""
|
||||||
|
for _, d := range p.Depends {
|
||||||
|
depends += fmt.Sprintf("%s ", d)
|
||||||
|
}
|
||||||
|
return depends
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Package) Load(r io.Reader) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
size int64
|
||||||
|
depends string = ""
|
||||||
|
section string = "DEFAULT"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser := configparser.New()
|
||||||
|
if err = parser.ParseReader(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range parser.Sections() {
|
||||||
|
if s == "DEFAULT" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
section = s
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if section == "DEFAULT" {
|
||||||
|
return fmt.Errorf("DATA does not contain any sections")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Name = section
|
||||||
|
|
||||||
|
if p.Version, err = parser.Get(section, "version"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if size, err = parser.GetInt64(section, "size"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Size = SizeFromBytes(size)
|
||||||
|
|
||||||
|
if p.Desc, err = parser.Get(section, "desc"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
depends, _ = parser.Get(section, "depends")
|
||||||
|
|
||||||
|
if depends == "" {
|
||||||
|
p.Depends = []string{}
|
||||||
|
} else {
|
||||||
|
p.Depends = strings.Split(depends, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
145
lib/lib/pool.go
Normal file
145
lib/lib/pool.go
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"bufio"
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/bigkevmcd/go-configparser"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Pool struct {
|
||||||
|
Maintainer string `json:"-"`
|
||||||
|
Pubkey string `json:"-"`
|
||||||
|
Size string `json:"-"`
|
||||||
|
|
||||||
|
Display string `json:"display"`
|
||||||
|
Branch string `json:"branch"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Dir string `json:"dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pool) Load(list *[]Package) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if p.Dir == "" {
|
||||||
|
return fmt.Errorf("pool directory is not specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = p.LoadInfo(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = p.LoadList(list); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pool) LoadList(list *[]Package) error {
|
||||||
|
var (
|
||||||
|
list_path string
|
||||||
|
list_file *os.File
|
||||||
|
gzip_reader io.Reader
|
||||||
|
header *tar.Header
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
list_path = path.Join(p.Dir, "LIST")
|
||||||
|
|
||||||
|
if list_file, err = os.Open(list_path); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer list_file.Close()
|
||||||
|
|
||||||
|
if gzip_reader, err = gzip.NewReader(bufio.NewReader(list_file)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := tar.NewReader(gzip_reader)
|
||||||
|
|
||||||
|
for header, err = reader.Next(); err == nil; header, err = reader.Next() {
|
||||||
|
if header.Typeflag != tar.TypeReg {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.Base(header.Name) != "DATA" {
|
||||||
|
return fmt.Errorf("LIST archive contains an unknown file")
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkg Package
|
||||||
|
|
||||||
|
if err = pkg.Load(reader); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg.Archive = path.Join(p.Dir, fmt.Sprintf("%s_%s.mpf", pkg.Name, pkg.Version))
|
||||||
|
pkg.Pool = p
|
||||||
|
|
||||||
|
*list = append(*list, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pool) LoadInfo() error {
|
||||||
|
var (
|
||||||
|
info_path string
|
||||||
|
info_file *os.File
|
||||||
|
section string
|
||||||
|
size int64
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
info_path = path.Join(p.Dir, "INFO")
|
||||||
|
|
||||||
|
if info_file, err = os.Open(info_path); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
parser := configparser.New()
|
||||||
|
|
||||||
|
if err = parser.ParseReader(bufio.NewReader(info_file)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
section = "DEFAULT"
|
||||||
|
|
||||||
|
for _, s := range parser.Sections() {
|
||||||
|
if s == "DEFAULT" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
section = s
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if section == "DEFAULT" {
|
||||||
|
return fmt.Errorf("DATA does not contain any sections")
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Name != section {
|
||||||
|
return fmt.Errorf("pool name (\"%s\") doesn't match with \"%s\"", p.Name, section)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Maintainer, err = parser.Get(p.Name, "maintainer"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if size, err = parser.GetInt64(section, "size"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Size = SizeFromBytes(size)
|
||||||
|
|
||||||
|
if p.Pubkey, err = parser.Get(section, "pubkey"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
104
lib/lib/util.go
Normal file
104
lib/lib/util.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetFiles(r io.Reader) ([]string, error) {
|
||||||
|
var (
|
||||||
|
gzip_reader io.Reader
|
||||||
|
header *tar.Header
|
||||||
|
result []string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if gzip_reader, err = gzip.NewReader(r); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := tar.NewReader(gzip_reader)
|
||||||
|
|
||||||
|
for header, err = reader.Next(); err == nil; header, err = reader.Next() {
|
||||||
|
if header.Typeflag != tar.TypeReg {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, header.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListToStr(l []string) string {
|
||||||
|
res := ""
|
||||||
|
for _, e := range l {
|
||||||
|
res += e + " "
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderError(c *fiber.Ctx, code int) error {
|
||||||
|
var msg string = "Server Error"
|
||||||
|
c.Status(code)
|
||||||
|
|
||||||
|
switch code {
|
||||||
|
case 404:
|
||||||
|
msg = "Not Found"
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Render("error", fiber.Map{
|
||||||
|
"msg": msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func SizeFromBytes(size int64) string {
|
||||||
|
if size > 1024*1024*1024 {
|
||||||
|
return fmt.Sprintf("%dGB", (size / 1024 / 1024 / 1024))
|
||||||
|
} else if size > 1024*1024 {
|
||||||
|
return fmt.Sprintf("%dMB", (size / 1024 / 1024))
|
||||||
|
} else if size > 1024 {
|
||||||
|
return fmt.Sprintf("%dKB", (size / 1024))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%dB", size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TimePassed(t time.Time) string {
|
||||||
|
diff := time.Since(t)
|
||||||
|
res := fmt.Sprintf(
|
||||||
|
"%ds ago",
|
||||||
|
int(diff.Seconds()),
|
||||||
|
)
|
||||||
|
|
||||||
|
if diff.Minutes() > 1 {
|
||||||
|
res = fmt.Sprintf(
|
||||||
|
"%dm and %ds ago",
|
||||||
|
int(diff.Minutes()), int(diff.Seconds())-(int(diff.Minutes())*60),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff.Hours() > 1 {
|
||||||
|
res = fmt.Sprintf("%dh and %dm ago",
|
||||||
|
int(diff.Hours()),
|
||||||
|
int(diff.Minutes())-(int(diff.Hours())*60),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func SanitizeXSS(s string) string {
|
||||||
|
var bad []string = []string{"~", "'", "\"", "/", "<", ">", "?", "=", "#", "(", ")", "{", "}", "*", "!", "`", "[", "]"}
|
||||||
|
|
||||||
|
for _, c := range bad {
|
||||||
|
s = strings.ReplaceAll(s, c, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
68
lib/user.go
68
lib/user.go
@ -7,54 +7,54 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
Cookie string
|
Cookie string
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUser(c *fiber.Ctx) (User, error) {
|
func GetUser(c *fiber.Ctx) (User, error) {
|
||||||
users, err := LoadUsers()
|
users, err := LoadUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return User{}, err
|
return User{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, u := range users {
|
for i, u := range users {
|
||||||
if c.Cookies("auth") == u.Cookie {
|
if c.Cookies("auth") == u.Cookie {
|
||||||
return users[i], nil
|
return users[i], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return User{}, fmt.Errorf("user not found")
|
return User{}, fmt.Errorf("user not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadUsers() ([]User, error) {
|
func LoadUsers() ([]User, error) {
|
||||||
var users []User
|
var users []User
|
||||||
|
|
||||||
rows, err := Db.Query("SELECT * FROM users")
|
rows, err := Db.Query("SELECT * FROM users")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return users, err
|
return users, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var u User
|
var u User
|
||||||
rows.Scan(&u.Username, &u.Password, &u.Cookie)
|
rows.Scan(&u.Username, &u.Password, &u.Cookie)
|
||||||
users = append(users, u)
|
users = append(users, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateUser(u User) error {
|
func UpdateUser(u User) error {
|
||||||
smt, err := Db.Prepare("UPDATE users SET password=?, cookie=? WHERE username=?")
|
smt, err := Db.Prepare("UPDATE users SET password=?, cookie=? WHERE username=?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = smt.Exec(u.Password, u.Cookie, u.Username)
|
_, err = smt.Exec(u.Password, u.Cookie, u.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
56
lib/util.go
56
lib/util.go
@ -12,46 +12,46 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func GetFTime() string {
|
func GetFTime() string {
|
||||||
return time.Now().Format("01/02/2006")
|
return time.Now().Format("01/02/2006")
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRandom() string {
|
func GetRandom() string {
|
||||||
buf := make([]byte, 128)
|
buf := make([]byte, 128)
|
||||||
_, err := rand.Read(buf)
|
_, err := rand.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to get random bytes: %s", err.Error())
|
log.Fatalf("Failed to get random bytes: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetSHA256(buf)
|
return GetSHA256(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSHA256(s []byte) string {
|
func GetSHA256(s []byte) string {
|
||||||
sum := sha256.Sum256(s)
|
sum := sha256.Sum256(s)
|
||||||
return fmt.Sprintf("%x", sum)
|
return fmt.Sprintf("%x", sum)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ContainsCase(s1 string, s2 string) bool {
|
func ContainsCase(s1 string, s2 string) bool {
|
||||||
return strings.Contains(
|
return strings.Contains(
|
||||||
strings.ToLower(s1), strings.ToLower(s2),
|
strings.ToLower(s1), strings.ToLower(s2),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenderError(c *fiber.Ctx, code int) error{
|
func RenderError(c *fiber.Ctx, code int) error {
|
||||||
var msg string = "Server Error"
|
var msg string = "Server Error"
|
||||||
c.Status(code)
|
c.Status(code)
|
||||||
|
|
||||||
switch code {
|
switch code {
|
||||||
case 404:
|
case 404:
|
||||||
msg = "Not Found"
|
msg = "Not Found"
|
||||||
case 500:
|
case 500:
|
||||||
msg = "Server error"
|
msg = "Server error"
|
||||||
case 403:
|
case 403:
|
||||||
msg = "Forbidden"
|
msg = "Forbidden"
|
||||||
case 400:
|
case 400:
|
||||||
msg = "Bad request"
|
msg = "Bad request"
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render("error", fiber.Map{
|
return c.Render("error", fiber.Map{
|
||||||
"msg": msg,
|
"msg": msg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
190
lib/vuln.go
190
lib/vuln.go
@ -7,131 +7,131 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Vuln struct {
|
type Vuln struct {
|
||||||
ID string
|
ID string
|
||||||
Desc string
|
Desc string
|
||||||
Source string
|
Source string
|
||||||
Severity string
|
Severity string
|
||||||
Package string
|
Package string
|
||||||
Versions string
|
Versions string
|
||||||
Status string
|
Status string
|
||||||
Message string
|
Message string
|
||||||
Author string
|
Author string
|
||||||
Date string
|
Date string
|
||||||
Updated string
|
Updated string
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidSeverity(s string) bool {
|
func ValidSeverity(s string) bool {
|
||||||
switch s {
|
switch s {
|
||||||
case "Low":
|
case "Low":
|
||||||
return true
|
return true
|
||||||
case "Medium":
|
case "Medium":
|
||||||
return true
|
return true
|
||||||
case "High":
|
case "High":
|
||||||
return true
|
return true
|
||||||
case "Critical":
|
case "Critical":
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Vuln) StatusColor() string {
|
func (v Vuln) StatusColor() string {
|
||||||
switch v.Status {
|
switch v.Status {
|
||||||
case "Waiting for review":
|
case "Waiting for review":
|
||||||
return "blue"
|
return "blue"
|
||||||
case "Ongoing review":
|
case "Ongoing review":
|
||||||
return "blue"
|
return "blue"
|
||||||
case "Working on a patch":
|
case "Working on a patch":
|
||||||
return "blue"
|
return "blue"
|
||||||
case "Won't patch":
|
case "Won't patch":
|
||||||
return "red"
|
return "red"
|
||||||
case "Patched":
|
case "Patched":
|
||||||
return "green"
|
return "green"
|
||||||
case "Not affected":
|
case "Not affected":
|
||||||
return "red"
|
return "red"
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetID() string {
|
func GetID() string {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
mic := strconv.FormatInt(now.UnixMicro(), 10)
|
mic := strconv.FormatInt(now.UnixMicro(), 10)
|
||||||
sig := GetSHA256([]byte(mic))[:5]
|
sig := GetSHA256([]byte(mic))[:5]
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"MPSI-%s%s-%s",
|
"MPSI-%s%s-%s",
|
||||||
now.Format("06"), now.Format("01"), sig,
|
now.Format("06"), now.Format("01"), sig,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadVulns() ([]Vuln, error) {
|
func LoadVulns() ([]Vuln, error) {
|
||||||
var vulns []Vuln
|
var vulns []Vuln
|
||||||
|
|
||||||
rows, err := Db.Query("SELECT * FROM vulns")
|
rows, err := Db.Query("SELECT * FROM vulns")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return vulns, err
|
return vulns, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var v Vuln
|
var v Vuln
|
||||||
rows.Scan(
|
rows.Scan(
|
||||||
&v.ID, &v.Desc, &v.Source, &v.Severity,
|
&v.ID, &v.Desc, &v.Source, &v.Severity,
|
||||||
&v.Package, &v.Versions, &v.Status, &v.Message,
|
&v.Package, &v.Versions, &v.Status, &v.Message,
|
||||||
&v.Author, &v.Date, &v.Updated)
|
&v.Author, &v.Date, &v.Updated)
|
||||||
vulns = append(vulns, v)
|
vulns = append(vulns, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return vulns, nil
|
return vulns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindVuln(id string) (Vuln, bool) {
|
func FindVuln(id string) (Vuln, bool) {
|
||||||
var vuln Vuln
|
var vuln Vuln
|
||||||
|
|
||||||
smt, err := Db.Prepare("SELECT * FROM vulns WHERE id=?")
|
smt, err := Db.Prepare("SELECT * FROM vulns WHERE id=?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return vuln, false
|
return vuln, false
|
||||||
}
|
}
|
||||||
|
|
||||||
row := smt.QueryRow(id)
|
row := smt.QueryRow(id)
|
||||||
err = row.Scan(
|
err = row.Scan(
|
||||||
&vuln.ID, &vuln.Desc, &vuln.Source, &vuln.Severity,
|
&vuln.ID, &vuln.Desc, &vuln.Source, &vuln.Severity,
|
||||||
&vuln.Package, &vuln.Versions, &vuln.Status, &vuln.Message,
|
&vuln.Package, &vuln.Versions, &vuln.Status, &vuln.Message,
|
||||||
&vuln.Author, &vuln.Date, &vuln.Updated)
|
&vuln.Author, &vuln.Date, &vuln.Updated)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return vuln, false
|
return vuln, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return vuln, true
|
return vuln, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddVuln(v Vuln) error{
|
func AddVuln(v Vuln) error {
|
||||||
smt, err := Db.Prepare("INSERT INTO vulns VALUES(?,?,?,?,?,?,?,?,?,?,?)")
|
smt, err := Db.Prepare("INSERT INTO vulns VALUES(?,?,?,?,?,?,?,?,?,?,?)")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = smt.Exec(&v.ID, &v.Desc, &v.Source, &v.Severity,
|
_, err = smt.Exec(&v.ID, &v.Desc, &v.Source, &v.Severity,
|
||||||
&v.Package, &v.Versions, &v.Status, &v.Message,
|
&v.Package, &v.Versions, &v.Status, &v.Message,
|
||||||
&v.Author, &v.Date, &v.Updated)
|
&v.Author, &v.Date, &v.Updated)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateVuln(v Vuln) error {
|
func UpdateVuln(v Vuln) error {
|
||||||
smt, err := Db.Prepare("UPDATE vulns SET status=?, message=?, author=?, severity=?, updated=? WHERE id=?")
|
smt, err := Db.Prepare("UPDATE vulns SET status=?, message=?, author=?, severity=?, updated=? WHERE id=?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = smt.Exec(v.Status, v.Message,
|
_, err = smt.Exec(v.Status, v.Message,
|
||||||
v.Author, v.Severity, GetFTime(), v.ID)
|
v.Author, v.Severity, GetFTime(), v.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
58
main.go
58
main.go
@ -16,7 +16,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@ -30,39 +30,39 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(log.Lshortfile | log.Ltime)
|
log.SetFlags(log.Lshortfile | log.Ltime)
|
||||||
|
|
||||||
engine := html.New("./templates", ".html")
|
engine := html.New("./templates", ".html")
|
||||||
app := fiber.New(fiber.Config{
|
app := fiber.New(fiber.Config{
|
||||||
DisableStartupMessage: true,
|
DisableStartupMessage: true,
|
||||||
Views: engine,
|
Views: engine,
|
||||||
})
|
})
|
||||||
|
|
||||||
err := lib.LoadDatabase()
|
err := lib.LoadDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to load database: %s", err.Error())
|
log.Fatalf("Failed to load database: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Static("/", "./public")
|
app.Static("/", "./public")
|
||||||
app.Get("/", routes.GETIndex)
|
app.Get("/", routes.GETIndex)
|
||||||
app.Get("/details/:id", routes.GETDetails)
|
app.Get("/details/:id", routes.GETDetails)
|
||||||
|
|
||||||
app.Get("/login", routes.GETLogin)
|
app.Get("/login", routes.GETLogin)
|
||||||
app.Post("/login", routes.POSTLogin)
|
app.Post("/login", routes.POSTLogin)
|
||||||
|
|
||||||
app.Use("/manage", routes.MiddleAuth)
|
app.Use("/manage", routes.MiddleAuth)
|
||||||
app.Get("/manage", routes.GETManage)
|
app.Get("/manage", routes.GETManage)
|
||||||
app.Get("/manage/logout", routes.GETLogout)
|
app.Get("/manage/logout", routes.GETLogout)
|
||||||
app.Post("/manage/new", routes.POSTNew)
|
app.Post("/manage/new", routes.POSTNew)
|
||||||
app.Post("/manage/status", routes.POSTStatus)
|
app.Post("/manage/status", routes.POSTStatus)
|
||||||
|
|
||||||
app.Get("*", func(c *fiber.Ctx) error {
|
app.Get("*", func(c *fiber.Ctx) error {
|
||||||
return lib.RenderError(c, 404)
|
return lib.RenderError(c, 404)
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Printf("Starting MatterLinux Security Tracker on port 9876")
|
log.Printf("Starting MatterLinux Security Tracker on port 9876")
|
||||||
err = app.Listen(":9876")
|
err = app.Listen(":9876")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error starting server: %s", err)
|
log.Fatalf("Error starting server: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
.vuln {
|
.vuln {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
background: var(--dark-second);
|
background: var(--dark-second);
|
||||||
border: solid 1px var(--bright-main);
|
border: solid 1px var(--bright-second);
|
||||||
color: var(--bright-second);
|
color: var(--bright-second);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +113,7 @@
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|
||||||
background: var(--dark-second);
|
background: var(--dark-second);
|
||||||
border: solid 1px var(--bright-main);
|
border: solid 1px var(--bright-second);
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-header {
|
.search-header {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
form {
|
form {
|
||||||
background: var(--dark-second);
|
background: var(--dark-second);
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
border: solid 1px var(--bright-main);
|
border: solid 1px var(--bright-second);
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -3,7 +3,7 @@ main a {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: var(--bright-main);
|
color: var(--bright-second);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
@ -15,7 +15,7 @@ main a:hover {
|
|||||||
form {
|
form {
|
||||||
background: var(--dark-second);
|
background: var(--dark-second);
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
border: solid 1px var(--bright-main);
|
border: solid 1px var(--bright-second);
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
118
routes/index.go
118
routes/index.go
@ -13,78 +13,78 @@ import (
|
|||||||
var PAGE_SIZE = 32
|
var PAGE_SIZE = 32
|
||||||
|
|
||||||
func GetPage(c *fiber.Ctx) (int, int, int) {
|
func GetPage(c *fiber.Ctx) (int, int, int) {
|
||||||
page, err := strconv.Atoi(c.Query("p"))
|
page, err := strconv.Atoi(c.Query("p"))
|
||||||
if err != nil || page <= 0 {
|
if err != nil || page <= 0 {
|
||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return page, page*PAGE_SIZE, (page*PAGE_SIZE)-PAGE_SIZE
|
return page, page * PAGE_SIZE, (page * PAGE_SIZE) - PAGE_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
func GETDetails(c *fiber.Ctx) error {
|
func GETDetails(c *fiber.Ctx) error {
|
||||||
id := c.Params("id")
|
id := c.Params("id")
|
||||||
if id == "" || !strings.HasPrefix(id, "MPSI-") {
|
if id == "" || !strings.HasPrefix(id, "MPSI-") {
|
||||||
return lib.RenderError(c, 404)
|
return lib.RenderError(c, 404)
|
||||||
}
|
}
|
||||||
|
|
||||||
v, suc := lib.FindVuln(id)
|
v, suc := lib.FindVuln(id)
|
||||||
if !suc {
|
if !suc {
|
||||||
return lib.RenderError(c, 404)
|
return lib.RenderError(c, 404)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render("details", fiber.Map{
|
return c.Render("details", fiber.Map{
|
||||||
"v": v,
|
"v": v,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GETIndex(c *fiber.Ctx) error {
|
func GETIndex(c *fiber.Ctx) error {
|
||||||
cur, max, min := GetPage(c)
|
cur, max, min := GetPage(c)
|
||||||
search_qu := c.Query("q")
|
search_qu := c.Query("q")
|
||||||
search_in := c.Query("i")
|
search_in := c.Query("i")
|
||||||
|
|
||||||
vulns, err := lib.LoadVulns()
|
vulns, err := lib.LoadVulns()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to load vulns: %s", err.Error())
|
log.Printf("Failed to load vulns: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
results := []lib.Vuln{}
|
results := []lib.Vuln{}
|
||||||
for i := len(vulns)-1; i >= 0; i-- {
|
for i := len(vulns) - 1; i >= 0; i-- {
|
||||||
if i >= max || i < min {
|
if i >= max || i < min {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
switch search_in {
|
switch search_in {
|
||||||
case "desc":
|
case "desc":
|
||||||
if !lib.ContainsCase(vulns[i].Desc, search_qu){
|
if !lib.ContainsCase(vulns[i].Desc, search_qu) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case "id":
|
case "id":
|
||||||
if !lib.ContainsCase(vulns[i].ID, search_qu) {
|
if !lib.ContainsCase(vulns[i].ID, search_qu) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case "pkg":
|
case "pkg":
|
||||||
if !lib.ContainsCase(vulns[i].Package, search_qu) {
|
if !lib.ContainsCase(vulns[i].Package, search_qu) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case "status":
|
case "status":
|
||||||
if !lib.ContainsCase(vulns[i].Status, search_qu) {
|
if !lib.ContainsCase(vulns[i].Status, search_qu) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
results = append(results, vulns[i])
|
results = append(results, vulns[i])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pages := int64(math.Ceil(float64(len(results))/float64(PAGE_SIZE)))
|
pages := int64(math.Ceil(float64(len(results)) / float64(PAGE_SIZE)))
|
||||||
return c.Render("index", fiber.Map{
|
return c.Render("index", fiber.Map{
|
||||||
"pages": pages,
|
"pages": pages,
|
||||||
"current": cur,
|
"current": cur,
|
||||||
"next": cur+1,
|
"next": cur + 1,
|
||||||
"prev": cur-1,
|
"prev": cur - 1,
|
||||||
"vulns": results,
|
"vulns": results,
|
||||||
"query": search_qu,
|
"query": search_qu,
|
||||||
"in": search_in,
|
"in": search_in,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -8,47 +8,47 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func POSTLogin(c *fiber.Ctx) error {
|
func POSTLogin(c *fiber.Ctx) error {
|
||||||
body := struct{
|
body := struct {
|
||||||
Username string `form:"username"`
|
Username string `form:"username"`
|
||||||
Password string `form:"password"`
|
Password string `form:"password"`
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
err := c.BodyParser(&body)
|
err := c.BodyParser(&body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lib.RenderError(c, 400)
|
return lib.RenderError(c, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := lib.LoadUsers()
|
users, err := lib.LoadUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to load users: %s", err.Error())
|
log.Printf("Failed to load users: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
if u.Username == u.Username &&
|
if u.Username == u.Username &&
|
||||||
u.Password == lib.GetSHA256([]byte(body.Password)) {
|
u.Password == lib.GetSHA256([]byte(body.Password)) {
|
||||||
u.Cookie = lib.GetRandom()
|
u.Cookie = lib.GetRandom()
|
||||||
c.Cookie(&fiber.Cookie{
|
c.Cookie(&fiber.Cookie{
|
||||||
Name: "auth",
|
Name: "auth",
|
||||||
Value: u.Cookie,
|
Value: u.Cookie,
|
||||||
})
|
})
|
||||||
err = lib.UpdateUser(u)
|
err = lib.UpdateUser(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to update user: %s", err.Error())
|
log.Printf("Failed to update user: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
return c.Redirect("/manage")
|
return c.Redirect("/manage")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Status(403)
|
c.Status(403)
|
||||||
return c.Render("login", fiber.Map{})
|
return c.Render("login", fiber.Map{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GETLogin(c *fiber.Ctx) error {
|
func GETLogin(c *fiber.Ctx) error {
|
||||||
if c.Cookies("auth") != "" {
|
if c.Cookies("auth") != "" {
|
||||||
return c.Redirect("/manage")
|
return c.Redirect("/manage")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render("login", fiber.Map{})
|
return c.Render("login", fiber.Map{})
|
||||||
}
|
}
|
||||||
|
@ -8,49 +8,49 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func MiddleAuth(c *fiber.Ctx) error {
|
func MiddleAuth(c *fiber.Ctx) error {
|
||||||
cookie := c.Cookies("auth")
|
cookie := c.Cookies("auth")
|
||||||
|
|
||||||
if cookie == "" {
|
if cookie == "" {
|
||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := lib.LoadUsers()
|
users, err := lib.LoadUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to load users: %s", err.Error())
|
log.Printf("Failed to load users: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
if u.Cookie == "notset" || u.Cookie == "" {
|
if u.Cookie == "notset" || u.Cookie == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if cookie == u.Cookie {
|
if cookie == u.Cookie {
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ClearCookie("auth")
|
c.ClearCookie("auth")
|
||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
}
|
}
|
||||||
|
|
||||||
func GETManage(c *fiber.Ctx) error {
|
func GETManage(c *fiber.Ctx) error {
|
||||||
return c.Render("manage", fiber.Map{})
|
return c.Render("manage", fiber.Map{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GETLogout(c *fiber.Ctx) error {
|
func GETLogout(c *fiber.Ctx) error {
|
||||||
user, err := lib.GetUser(c)
|
user, err := lib.GetUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to load user: %s", err.Error())
|
log.Printf("Failed to load user: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Cookie = "notset"
|
user.Cookie = "notset"
|
||||||
err = lib.UpdateUser(user)
|
err = lib.UpdateUser(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to save users: %s", err.Error())
|
log.Printf("Failed to save users: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
}
|
}
|
||||||
|
@ -8,48 +8,48 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func POSTNew(c *fiber.Ctx) error {
|
func POSTNew(c *fiber.Ctx) error {
|
||||||
body := struct{
|
body := struct {
|
||||||
Desc string `form:"desc"`
|
Desc string `form:"desc"`
|
||||||
Source string `form:"source"`
|
Source string `form:"source"`
|
||||||
Severity string `form:"severity"`
|
Severity string `form:"severity"`
|
||||||
Package string `form:"package"`
|
Package string `form:"package"`
|
||||||
Versions string `form:"versions"`
|
Versions string `form:"versions"`
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
err := c.BodyParser(&body)
|
err := c.BodyParser(&body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lib.RenderError(c, 400)
|
return lib.RenderError(c, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := lib.GetUser(c)
|
user, err := lib.GetUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to get the user: %s", err.Error())
|
log.Printf("Failed to get the user: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lib.ValidSeverity(body.Severity){
|
if !lib.ValidSeverity(body.Severity) {
|
||||||
return lib.RenderError(c, 400)
|
return lib.RenderError(c, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := lib.Vuln{
|
v := lib.Vuln{
|
||||||
ID: lib.GetID(),
|
ID: lib.GetID(),
|
||||||
Desc: body.Desc,
|
Desc: body.Desc,
|
||||||
Source: body.Source,
|
Source: body.Source,
|
||||||
Severity: body.Severity,
|
Severity: body.Severity,
|
||||||
Package: body.Package,
|
Package: body.Package,
|
||||||
Versions: body.Versions,
|
Versions: body.Versions,
|
||||||
Status: "Waiting for review",
|
Status: "Waiting for review",
|
||||||
Message: "This vulnerability is waiting for a review from the maintainers",
|
Message: "This vulnerability is waiting for a review from the maintainers",
|
||||||
Author: user.Username,
|
Author: user.Username,
|
||||||
Date: lib.GetFTime(),
|
Date: lib.GetFTime(),
|
||||||
Updated: lib.GetFTime(),
|
Updated: lib.GetFTime(),
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lib.AddVuln(v)
|
err = lib.AddVuln(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to add vuln: %s", err.Error())
|
log.Printf("Failed to add vuln: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Redirect("/manage")
|
return c.Redirect("/manage")
|
||||||
}
|
}
|
||||||
|
@ -10,39 +10,39 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func POSTStatus(c *fiber.Ctx) error {
|
func POSTStatus(c *fiber.Ctx) error {
|
||||||
body := struct{
|
body := struct {
|
||||||
ID string `form:"id"`
|
ID string `form:"id"`
|
||||||
Status string `form:"status"`
|
Status string `form:"status"`
|
||||||
Message string `form:"message"`
|
Message string `form:"message"`
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
err := c.BodyParser(&body)
|
err := c.BodyParser(&body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lib.RenderError(c, 400)
|
return lib.RenderError(c, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := lib.GetUser(c)
|
user, err := lib.GetUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to get the user: %s", err.Error())
|
log.Printf("Failed to get the user: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln, suc := lib.FindVuln(body.ID)
|
vuln, suc := lib.FindVuln(body.ID)
|
||||||
if !suc {
|
if !suc {
|
||||||
return lib.RenderError(c, 404)
|
return lib.RenderError(c, 404)
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln.Message = body.Message
|
vuln.Message = body.Message
|
||||||
vuln.Status = body.Status
|
vuln.Status = body.Status
|
||||||
if vuln.Author != user.Username && !strings.Contains(vuln.Author, ", "+user.Username){
|
if vuln.Author != user.Username && !strings.Contains(vuln.Author, ", "+user.Username) {
|
||||||
vuln.Author += ", "+user.Username
|
vuln.Author += ", " + user.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lib.UpdateVuln(vuln)
|
err = lib.UpdateVuln(vuln)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to update the vuln: %s", err.Error())
|
log.Printf("Failed to update the vuln: %s", err.Error())
|
||||||
return lib.RenderError(c, 500)
|
return lib.RenderError(c, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Redirect("/manage")
|
return c.Redirect("/manage")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user