Skip to content
This repository was archived by the owner on Jun 24, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
41 changes: 5 additions & 36 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,6 @@ orbs:
go: circleci/go@1.6.0

jobs:
bindata:
executor:
name: go/default
tag: '1.16'

steps:
- checkout
- run:
name: Install go-bindata
command: |
go get github.com/go-bindata/go-bindata/...
- run:
name: Generate bindata.go
command: go generate -x
- persist_to_workspace:
root: .
paths:
- "bindata.go"

build:
parameters:
go_version:
Expand All @@ -41,8 +22,6 @@ jobs:
steps:
- checkout
- go/mod-download-cached
- attach_workspace:
at: .
- run:
name: Install SQLite
command: |
Expand Down Expand Up @@ -97,32 +76,22 @@ jobs:
workflows:
Branch builds:
jobs:
- bindata:
filters: &filters-branch
branches:
ignore: master
- build:
requires:
- bindata
matrix:
parameters:
go_version: ["1.15", "1.16"]
filters:
<<: *filters-branch
go_version: ["1.16"]
filters: &filters-branch
branches:
ignore: master

Release:
jobs:
- bindata:
- build:
filters: &filters-release
branches:
ignore: /.*/
tags:
only: /^v.*/
- build:
requires:
- bindata
filters:
<<: *filters-release
- hold:
type: approval
requires:
Expand Down
14 changes: 1 addition & 13 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
GOBINDATA = $(shell go env GOPATH)/bin/go-bindata

.PHONY: all
all: build

.PHONY: build
build: assets scan
build: scan

dirs := $(shell go list -f '{{.Dir}}' ./...)
gofiles := $(foreach dir,$(dirs),$(wildcard $(dir)/*.go))

scan: $(gofiles)
go build

.PHONY: assets
assets: bindata.go

bindata.go: $(GOBINDATA) views/*.html
go generate

$(GOBINDATA):
go get github.com/go-bindata/go-bindata/...


.PHONY: sample-data
sample-data:
curl -s -H "Content-Type: application/json" \
Expand Down
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Scan is a small web service for recording and displaying [Masscan](https://githu

## Building and Installation

As of v0.8.1 Scan uses Go modules. Go 1.13 or newer is required to build.
As of v0.8.1 Scan uses Go modules. Go 1.16 or newer is required to build.

Precompiled binaries for Linux on x86-64 are available on the GitHub releases page.

Expand All @@ -25,14 +25,12 @@ Or macOS:
brew install sqlite
```

To generate the `scan` binary run:
To build the `scan` binary run:

```
make
go build
```

This will generate the `bindata.go` containing static assets and build the binary.

## Database

Scan stores results in a SQLite database. The database is automatically created and maintained at startup.
Expand Down
4 changes: 2 additions & 2 deletions admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (app *App) adminHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
session.Save(r, w)
}
tmpl.ExecuteTemplate(w, "index", data)
app.tmpl.ExecuteTemplate(w, "index", data)
return
}
v := session.Values["user"]
Expand Down Expand Up @@ -88,7 +88,7 @@ func (app *App) adminHandler(w http.ResponseWriter, r *http.Request) {
}
}

tmpl.ExecuteTemplate(w, "admin", data)
app.tmpl.ExecuteTemplate(w, "admin", data)
}

var (
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/jamesog/scan

go 1.14
go 1.16

require (
cloud.google.com/go v0.57.0 // indirect
Expand Down
60 changes: 0 additions & 60 deletions go.sum

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions job.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (app *App) newJob(w http.ResponseWriter, r *http.Request) {
}
if _, ok := session.Values["user"]; !ok {
data := jobData{indexData: indexData{URI: r.RequestURI}}
tmpl.ExecuteTemplate(w, "job", data)
app.tmpl.ExecuteTemplate(w, "job", data)
return
}
v := session.Values["user"]
Expand Down Expand Up @@ -113,7 +113,7 @@ func (app *App) newJob(w http.ResponseWriter, r *http.Request) {
Jobs: jobs,
}

tmpl.ExecuteTemplate(w, "job", data)
app.tmpl.ExecuteTemplate(w, "job", data)
}

// Handler for GET /jobs
Expand Down
6 changes: 3 additions & 3 deletions job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestUpdateJob(t *testing.T) {
func TestJobHandler(t *testing.T) {
db := createDB("TestJobHandler")
defer db.Close()
app := App{db: db}
app := setup(db)

r := httptest.NewRequest("GET", "/job", nil)
w := httptest.NewRecorder()
Expand Down Expand Up @@ -84,7 +84,7 @@ func TestJobHandler(t *testing.T) {
func TestJobsHandler(t *testing.T) {
db := createDB("TestJobsHandler")
defer db.Close()
app := App{db: db}
app := setup(db)

r := httptest.NewRequest("GET", "/jobs", nil)
w := httptest.NewRecorder()
Expand All @@ -104,7 +104,7 @@ func TestJobsHandler(t *testing.T) {
func TestJobResultsHandler(t *testing.T) {
db := createDB("TestJobResultsHandler")
defer db.Close()
app := App{db: db}
app := setup(db)

data := bytes.NewBuffer([]byte(`[{"ip":"192.0.2.1","ports":[{"port":80,"proto":"tcp","status":"open","reason":"syn-ack","ttl":57}]}]`))

Expand Down
83 changes: 17 additions & 66 deletions scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
package main

import (
"bytes"
"crypto/tls"
"database/sql"
"embed"
"encoding/json"
"errors"
"flag"
Expand All @@ -13,7 +13,6 @@ import (
"io"
"io/ioutil"
"log"
"mime"
"net"
"net/http"
"os"
Expand All @@ -38,9 +37,13 @@ var (
dataDir string
httpsAddr string
verbose bool
)

// HTML templates
tmpl *template.Template
var (
//go:embed views/*
views embed.FS
//go:embed static
static embed.FS
)

type storage interface {
Expand Down Expand Up @@ -76,7 +79,8 @@ type indexData struct {
}

type App struct {
db storage
db storage
tmpl *template.Template
}

// Handler for GET /
Expand All @@ -95,7 +99,7 @@ func (app *App) index(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
session.Save(r, w)
}
tmpl.ExecuteTemplate(w, "index", data)
app.tmpl.ExecuteTemplate(w, "index.html", data)
return
}
v := session.Values["user"]
Expand Down Expand Up @@ -133,7 +137,7 @@ func (app *App) index(w http.ResponseWriter, r *http.Request) {
Submission: sub,
Data: results,
}
tmpl.ExecuteTemplate(w, "index", data)
app.tmpl.ExecuteTemplate(w, "index", data)
}

func (app *App) saveResults(w http.ResponseWriter, r *http.Request, now time.Time) (int64, error) {
Expand Down Expand Up @@ -258,43 +262,6 @@ func redirectHTTPS(next http.Handler) http.Handler {
})
}

type assetMap map[string]asset

var assets assetMap

// loadAssetsFromDir gets all assets whose parent directory is "name" and
// returns a map of the asset path to the asset function.
func loadAssetsFromDir(name string) assetMap {
assets = make(assetMap)
for b := range _bindata {
if strings.HasPrefix(b, name+"/") {
a, err := _bindata[b]()
if err != nil {
log.Printf("Failed to load asset %s: %v", b, err)
}
assets[b] = *a
}
}
return assets
}

// staticHandler returns a static asset from the map generated by
// loadAssetsFromDir.
func staticHandler(w http.ResponseWriter, r *http.Request) {
path := strings.TrimPrefix(r.URL.Path, "/")
if a, ok := assets[path]; ok {
ct := mime.TypeByExtension(filepath.Ext(a.info.Name()))
if ct == "" {
ct = http.DetectContentType(a.bytes)
}
w.Header().Set("Content-Type", ct)
b := bytes.NewReader(a.bytes)
http.ServeContent(w, r, a.info.Name(), a.info.ModTime(), b)
}

http.NotFound(w, r)
}

func (app *App) setupRouter(middlewares ...func(http.Handler) http.Handler) *chi.Mux {
r := chi.NewRouter()
r.Use(middleware.RealIP)
Expand All @@ -303,8 +270,6 @@ func (app *App) setupRouter(middlewares ...func(http.Handler) http.Handler) *chi
r.Use(mw)
}

assets = loadAssetsFromDir("static")

r.Get("/", app.index)
r.Route("/admin", func(r chi.Router) {
r.Get("/", app.adminHandler)
Expand All @@ -320,36 +285,23 @@ func (app *App) setupRouter(middlewares ...func(http.Handler) http.Handler) *chi
r.Get("/logout", app.logoutHandler)
r.Post("/results", app.recvResults)
r.Put("/results/{id}", app.recvJobResults)
r.Get("/static/*", staticHandler)
r.Method(http.MethodGet, "/static/*", http.FileServer(http.FS(static)))
r.Post("/traceroute", app.recvTraceroute)
r.Get("/traceroute/{ip}", app.traceroute)

return r
}

func setupTemplates() {
func (app *App) setupTemplates() {
funcMap := template.FuncMap{
"join": func(sep string, s []string) string {
return strings.Join(s, sep)
},
}

tmpl = template.New("").Funcs(funcMap)

views, err := AssetDir("views")
if err != nil {
log.Fatal(err)
}

for _, file := range views {
b, err := Asset("views/" + file)
if err != nil {
log.Println(err)
continue
}
t := tmpl.New(filepath.Base(file))
template.Must(t.Parse(string(b)))
}
app.tmpl = template.Must(
template.New("").Funcs(funcMap).ParseFS(views, "views/*.html"),
)
}

func main() {
Expand Down Expand Up @@ -389,8 +341,6 @@ func main() {
}
app := &App{db: db}

setupTemplates()

var middlewares []func(http.Handler) http.Handler

if authDisabled {
Expand All @@ -410,6 +360,7 @@ func main() {
}

r := app.setupRouter(middlewares...)
app.setupTemplates()

// Common http.Server timeout values
readTimeout := 5 * time.Second
Expand Down
Loading