Skip to content
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 87 additions & 84 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,85 +1,88 @@
name: ci

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 0 * * *' # Runs every day at 00:00 UTC

jobs:
gotest:
name: Test ocr worker
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v6
with:
go-version: stable
id: go

- name: Check out code into the Go module directory
uses: actions/checkout@v6

- name: Build
run: go build -v ./...

- name: gofmt
run: |
GOFMTOUT=$(gofmt -l .)
if [[ ! -z "${GOFMTOUT}" ]]; then
echo "FATAL: gofmt violation(s), please fix"
echo $GOFMTOUT
exit -1
fi
- name: go vet
run: go vet ./...

- name: Test
run: go test -v ./...

build_push:
name: Build and Push
needs: [gotest]
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v6

- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5.10.0
with:
images: ashirt/ocr-worker
tags: |
type=sha
type=ref,event=branch
type=ref,event=pr
flavor: |
latest=false
- name: Login to Docker Hub
uses: docker/login-action@v3.7.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and Push PR
if: github.ref != 'refs/heads/main'
uses: docker/build-push-action@v6.18.0
with:
context: .
file: Dockerfile
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
push: true # Push with pr-### and sha-xxxxxxx tags

- name: Build and Push Latest
if: github.ref == 'refs/heads/main'
uses: docker/build-push-action@v6.18.0
with:
context: .
file: Dockerfile
tags: ${{ steps.docker_meta.outputs.tags }}, ashirt/ocr-worker:latest #Add latest tag for main
labels: ${{ steps.docker_meta.outputs.labels }}
name: ci

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 0 * * *' # Runs every day at 00:00 UTC

jobs:
gotest:
name: Test ocr worker
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v6
with:
go-version: stable
id: go

- name: Check out code into the Go module directory
uses: actions/checkout@v6

- name: Install packages
run: sudo apt install -y libtesseract-dev tesseract-ocr-eng

- name: Build
run: go build -v ./...

- name: gofmt
run: |
GOFMTOUT=$(gofmt -l .)
if [[ ! -z "${GOFMTOUT}" ]]; then
echo "FATAL: gofmt violation(s), please fix"
echo $GOFMTOUT
exit -1
fi
- name: go vet
run: go vet ./...

- name: Test
run: go test -v ./...

build_push:
name: Build and Push
needs: [gotest]
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v6

- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5.10.0
with:
images: ashirt/ocr-worker
tags: |
type=sha
type=ref,event=branch
type=ref,event=pr
flavor: |
latest=false
- name: Login to Docker Hub
uses: docker/login-action@v3.7.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and Push PR
if: github.ref != 'refs/heads/main'
uses: docker/build-push-action@v6.18.0
with:
context: .
file: Dockerfile
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
push: true # Push with pr-### and sha-xxxxxxx tags

- name: Build and Push Latest
if: github.ref == 'refs/heads/main'
uses: docker/build-push-action@v6.18.0
with:
context: .
file: Dockerfile
tags: ${{ steps.docker_meta.outputs.tags }}, ashirt/ocr-worker:latest #Add latest tag for main
labels: ${{ steps.docker_meta.outputs.labels }}
push: true
4 changes: 4 additions & 0 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ jobs:
- uses: actions/setup-go@v6
with:
go-version: stable

- name: Install packages
run: sudo apt install -y libtesseract-dev tesseract-ocr-eng

- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
Expand Down
37 changes: 20 additions & 17 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
FROM golang:1.25-alpine AS build

RUN mkdir app
COPY . ./app/
WORKDIR /go/app
RUN go build -v ./...

FROM alpine:latest

RUN apk add --no-cache tesseract-ocr && \
adduser -h /home/ashirt -S -D ashirt

USER ashirt
WORKDIR /home/ashirt

COPY --from=build /go/app/ocr-worker /home/ashirt/ocr-worker

FROM golang:1.25-alpine AS build

RUN mkdir app && \
apk add --no-cache build-base leptonica-dev tesseract-ocr-dev

COPY . ./app/
WORKDIR /go/app

RUN go build -v ./cmd/...

FROM alpine:latest

RUN apk add --no-cache tesseract-ocr tesseract-ocr-data-eng && \
adduser -h /home/ashirt -S -D ashirt

USER ashirt
WORKDIR /home/ashirt

COPY --from=build /go/app/ocr-worker /home/ashirt/ocr-worker

CMD ["ocr-worker"]
28 changes: 26 additions & 2 deletions cmd/ocr-worker/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
package main

import "fmt"
import (
"log"
"log/slog"
"net/http"
"os"

"github.com/ashirt-ops/ocr-worker/internal/handlers"
"github.com/ashirt-ops/ocr-worker/internal/textextractor"
"github.com/jrozner/weby/middleware"
"github.com/jrozner/weby/rlog"
)

func main() {
fmt.Println("Hello world!")
var handler slog.Handler = slog.NewTextHandler(os.Stdout, nil)

handler = rlog.RequestIDHandler{Handler: handler}
logger := slog.New(handler)

extractor := textextractor.NewTesseract()

env := handlers.New(extractor)
mux := env.Routes()

mux.Use(middleware.RequestID)
mux.Use(middleware.WrapResponse)
mux.Use(middleware.Logger(logger))

log.Fatal(http.ListenAndServe(":8080", mux))
}
11 changes: 11 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
module github.com/ashirt-ops/ocr-worker

go 1.25.6

require (
github.com/jrozner/weby v0.1.0
github.com/otiai10/gosseract v2.2.1+incompatible
)

require (
github.com/google/uuid v1.6.0 // indirect
github.com/otiai10/mint v1.6.3 // indirect
golang.org/x/net v0.49.0 // indirect
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jrozner/weby v0.1.0 h1:kI+DXnYHsSB6Kmmil8i7Wqh5O1oF1c1xOhnVSONh+BA=
github.com/jrozner/weby v0.1.0/go.mod h1:cBLmTAkOScydeEd02pmDkSeQfdZUQ9Y3r3hcLSUZrqI=
github.com/otiai10/gosseract v2.2.1+incompatible h1:Ry5ltVdpdp4LAa2bMjsSJH34XHVOV7XMi41HtzL8X2I=
github.com/otiai10/gosseract v2.2.1+incompatible/go.mod h1:XrzWItCzCpFRZ35n3YtVTgq5bLAhFIkascoRo8G32QE=
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
87 changes: 87 additions & 0 deletions internal/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package client

import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"io"
"net/http"
"time"
)

type Client struct {
*http.Client
base string
accessKey string
secretKey []byte
}

func New(base, accessKey string, secretKey []byte) *Client {
c := &http.Client{}
client := &Client{
Client: c,
base: base,
accessKey: accessKey,
secretKey: secretKey,
}

return client
}

func (c *Client) Do(r *http.Request) (*http.Response, error) {
date := time.Now().Format(time.RFC1123)

r.Header.Set("Date", date)

signature, err := generateSignature(r, c.secretKey)
if err != nil {
return nil, err
}

encodedSignature := base64.StdEncoding.EncodeToString(signature)

r.Header.Add("Authorization", fmt.Sprintf("%s:%s", c.accessKey, encodedSignature))

return c.Client.Do(r)
}

func generateSignature(r *http.Request, key []byte) ([]byte, error) {
// copy the body into somewhere that we can reset
body := bytes.NewBuffer([]byte{})
_, err := io.Copy(body, r.Body)
if err != nil {
return nil, err
}

// close the original body so we don't leak it
err = r.Body.Close()
if err != nil {
return nil, err
}

// shasum the body
requestBodySHA256 := sha256.New()
_, err = io.Copy(requestBodySHA256, r.Body)
if err != nil {
return nil, err
}

// reset the body so it can be read again
body.Reset()
r.Body = io.NopCloser(body)

m := new(bytes.Buffer)
m.WriteString(r.Method)
m.WriteString("\n")
m.WriteString(r.URL.RequestURI())
m.WriteString("\n")
m.WriteString(r.Header.Get("Date"))
m.WriteString("\n")
m.Write(requestBodySHA256.Sum(nil))

mac := hmac.New(sha256.New, key)
mac.Write(m.Bytes())
return mac.Sum(nil), nil
}
1 change: 1 addition & 0 deletions internal/client/evidence.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package client
1 change: 1 addition & 0 deletions internal/client/operations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package client
Loading
Loading