Skip to content

Commit 5ee6d9d

Browse files
committed
generate it!
1 parent 734d920 commit 5ee6d9d

File tree

21 files changed

+8165
-18
lines changed

21 files changed

+8165
-18
lines changed

.github/workflows/ci.yml

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build and Push Docker Image
1+
name: Build and Push Docker Images
22

33
on:
44
push:
@@ -8,15 +8,12 @@ on:
88

99
env:
1010
REGISTRY: ghcr.io
11-
IMAGE_NAME: ${{ github.repository }}/ctmon-ingest
11+
BACKEND_IMAGE_NAME: ${{ github.repository }}/ctmon-ingest
12+
UI_IMAGE_NAME: ${{ github.repository }}/ctmon-ui
1213

1314
jobs:
14-
build-and-push:
15+
test:
1516
runs-on: ubuntu-latest
16-
permissions:
17-
contents: read
18-
packages: write
19-
2017
steps:
2118
- name: Checkout repository
2219
uses: actions/checkout@v4
@@ -26,32 +23,97 @@ jobs:
2623
with:
2724
go-version: '1.23'
2825

29-
- name: Run tests
26+
- name: Run Go tests
3027
run: go test -v ./...
3128

29+
- name: Set up Node.js
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: '20'
33+
cache: 'npm'
34+
cache-dependency-path: ui/package-lock.json
35+
36+
- name: Install UI dependencies
37+
run: cd ui && npm ci
38+
39+
- name: Run UI linting
40+
run: cd ui && npm run lint
41+
42+
- name: Build UI
43+
run: cd ui && npm run build
44+
45+
build-and-push-backend:
46+
needs: test
47+
runs-on: ubuntu-latest
48+
permissions:
49+
contents: read
50+
packages: write
51+
52+
steps:
53+
- name: Checkout repository
54+
uses: actions/checkout@v4
55+
3256
- name: Log in to Container Registry
3357
uses: docker/login-action@v3
3458
with:
3559
registry: ${{ env.REGISTRY }}
3660
username: ${{ github.actor }}
3761
password: ${{ secrets.GITHUB_TOKEN }}
3862

39-
- name: Extract metadata
40-
id: meta
63+
- name: Extract backend metadata
64+
id: meta-backend
4165
uses: docker/metadata-action@v5
4266
with:
43-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
67+
images: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}
4468
tags: |
4569
type=ref,event=branch
4670
type=ref,event=pr
4771
type=sha
4872
type=raw,value=latest,enable={{is_default_branch}}
4973
50-
- name: Build and push Docker image
74+
- name: Build and push backend Docker image
5175
uses: docker/build-push-action@v5
5276
with:
5377
context: .
5478
push: true
55-
tags: ${{ steps.meta.outputs.tags }}
56-
labels: ${{ steps.meta.outputs.labels }}
79+
tags: ${{ steps.meta-backend.outputs.tags }}
80+
labels: ${{ steps.meta-backend.outputs.labels }}
5781
target: ctmon_ingest
82+
83+
build-and-push-ui:
84+
needs: test
85+
runs-on: ubuntu-latest
86+
permissions:
87+
contents: read
88+
packages: write
89+
90+
steps:
91+
- name: Checkout repository
92+
uses: actions/checkout@v4
93+
94+
- name: Log in to Container Registry
95+
uses: docker/login-action@v3
96+
with:
97+
registry: ${{ env.REGISTRY }}
98+
username: ${{ github.actor }}
99+
password: ${{ secrets.GITHUB_TOKEN }}
100+
101+
- name: Extract UI metadata
102+
id: meta-ui
103+
uses: docker/metadata-action@v5
104+
with:
105+
images: ${{ env.REGISTRY }}/${{ env.UI_IMAGE_NAME }}
106+
tags: |
107+
type=ref,event=branch
108+
type=ref,event=pr
109+
type=sha
110+
type=raw,value=latest,enable={{is_default_branch}}
111+
112+
- name: Build and push UI Docker image
113+
uses: docker/build-push-action@v5
114+
with:
115+
context: .
116+
push: true
117+
tags: ${{ steps.meta-ui.outputs.tags }}
118+
labels: ${{ steps.meta-ui.outputs.labels }}
119+
target: ui

Dockerfile

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Build stage
1+
# Go backend build stage
22
FROM golang:1.23-alpine AS builder
33

44
WORKDIR /app
@@ -18,7 +18,7 @@ COPY . .
1818
# Build the binary
1919
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o ctmon-ingest ./cmd/ctmon-ingest
2020

21-
# Runtime stage
21+
# Go backend runtime stage
2222
FROM alpine:latest AS ctmon_ingest
2323

2424
# Install ca-certificates for HTTPS requests
@@ -33,4 +33,42 @@ COPY --from=builder /app/ctmon-ingest .
3333
EXPOSE 8080
3434

3535
# Run the binary
36-
CMD ["./ctmon-ingest"]
36+
CMD ["./ctmon-ingest"]
37+
38+
# UI build stage
39+
FROM node:20-alpine AS ui-builder
40+
41+
WORKDIR /app
42+
43+
# Copy package files
44+
COPY ui/package*.json ./
45+
46+
# Install dependencies
47+
RUN npm ci
48+
49+
# Copy UI source code
50+
COPY ui/ ./
51+
52+
# Build the application
53+
RUN npm run build
54+
55+
# UI runtime stage
56+
FROM node:20-alpine AS ui
57+
58+
WORKDIR /app
59+
60+
# Copy built application
61+
COPY --from=ui-builder /app/.next/standalone ./
62+
COPY --from=ui-builder /app/.next/static ./.next/static
63+
COPY --from=ui-builder /app/public ./public
64+
65+
# Expose port
66+
EXPOSE 3000
67+
68+
# Set environment variables
69+
ENV NODE_ENV=production
70+
ENV HOSTNAME=0.0.0.0
71+
ENV PORT=3000
72+
73+
# Run the application
74+
CMD ["node", "server.js"]

schema.sql

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ CREATE TABLE ct_log_entries
4343
-- Other Key Parsed Certificate Fields
4444
serial_number String COMMENT 'Certificate serial number (hex string)',
4545
subject_alternative_names Array(String) COMMENT 'Array of Subject Alternative Names (DNS, IP, etc.)',
46+
name_suffixes Array(String) MATERIALIZED arrayDistinct(
47+
arrayFlatten(
48+
arrayMap(x -> arrayMap(
49+
i -> substring(x, i), arrayFilter(i -> i > 0, arrayMap(pos -> position(x, '.', pos), range(1, length(x) + 1)))
50+
),
51+
arrayConcat(subject_alternative_names, [subject_common_name])
52+
))
53+
) COMMENT 'All domain suffixes from subject_alternative_names and subject_common_name (e.g., .example.com, .com)',
4654
signature_algorithm LowCardinality(String) COMMENT 'Signature algorithm of the certificate',
4755
subject_public_key_algorithm LowCardinality(String) COMMENT 'Algorithm of the subject public key',
4856
subject_public_key_length UInt16 COMMENT 'Length of the subject public key (e.g., 2048, 256)',
@@ -85,7 +93,8 @@ CREATE TABLE ct_log_entries
8593
INDEX idx_sans subject_alternative_names TYPE bloom_filter GRANULARITY 4, -- For has(subject_alternative_names, 'value')
8694
INDEX idx_serial serial_number TYPE bloom_filter GRANULARITY 1,
8795
INDEX idx_not_after not_after TYPE minmax,
88-
INDEX idx_entry_timestamp entry_timestamp TYPE minmax
96+
INDEX idx_entry_timestamp entry_timestamp TYPE minmax,
97+
INDEX idx_name_suffixes name_suffixes TYPE bloom_filter GRANULARITY 4 -- For has(name_suffixes, 'value')
8998
)
9099
ENGINE = ReplacingMergeTree()
91100
PARTITION BY toYYYYMM(not_after) -- Partition by month of certificate expiry

ui/.gitignore

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.*
7+
.yarn/*
8+
!.yarn/patches
9+
!.yarn/plugins
10+
!.yarn/releases
11+
!.yarn/versions
12+
13+
# testing
14+
/coverage
15+
16+
# next.js
17+
/.next/
18+
/out/
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
.pnpm-debug.log*
32+
33+
# env files (can opt-in for committing if needed)
34+
.env*
35+
36+
# vercel
37+
.vercel
38+
39+
# typescript
40+
*.tsbuildinfo
41+
next-env.d.ts

ui/README.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Certificate Transparency Monitor
2+
3+
A web application for searching and monitoring SSL/TLS certificates from Certificate Transparency logs, similar to crt.sh. Built with Next.js and ClickHouse.
4+
5+
## Features
6+
7+
- **Multi-type Search**: Search certificates by domain name, common name, serial number, SHA-256 fingerprint, or issuer
8+
- **Detailed Certificate View**: View complete certificate information including subject, issuer, validity periods, and extensions
9+
- **Subject Alternative Names**: Display all SAN entries for certificates
10+
- **Certificate Transparency Logs**: Track which CT log each certificate was found in
11+
- **Responsive Design**: Works on desktop and mobile devices with dark mode support
12+
13+
## Tech Stack
14+
15+
- **Frontend**: Next.js 15 with React 19
16+
- **Styling**: Tailwind CSS 4
17+
- **Database**: ClickHouse
18+
- **Language**: TypeScript
19+
20+
## Prerequisites
21+
22+
- Node.js 18+
23+
- ClickHouse database with CT log data
24+
- Environment variables for ClickHouse connection
25+
26+
## Environment Variables
27+
28+
Create a `.env.local` file in the `ui/` directory with the following variables:
29+
30+
```bash
31+
CLICKHOUSE_HOST=localhost
32+
CLICKHOUSE_PORT=8123
33+
CLICKHOUSE_USER=default
34+
CLICKHOUSE_PASSWORD=your_password
35+
CLICKHOUSE_DATABASE=ct_logs
36+
```
37+
38+
## Installation
39+
40+
1. Install dependencies:
41+
```bash
42+
npm install
43+
```
44+
45+
2. Run the development server:
46+
```bash
47+
npm run dev
48+
```
49+
50+
3. Open [http://localhost:3000](http://localhost:3000) in your browser
51+
52+
## Database Schema
53+
54+
The application expects a ClickHouse table named `ct_log_entries` with the schema defined in `/schema.sql`. Key fields include:
55+
56+
- Certificate identifiers (SHA-256, serial number)
57+
- Subject and issuer information
58+
- Validity periods
59+
- Subject Alternative Names
60+
- Certificate extensions and key usage
61+
- CT log metadata
62+
63+
## API Endpoints
64+
65+
### Get Certificate Details
66+
```
67+
GET /api/certificate/{sha256}
68+
```
69+
70+
Returns complete certificate information for a given SHA-256 fingerprint.
71+
72+
## Search Types
73+
74+
1. **Domain/SAN**: Search by domain name or Subject Alternative Name
75+
- Example: `example.com`, `*.example.com`
76+
77+
2. **Common Name**: Search by certificate Common Name field
78+
- Example: `www.example.com`
79+
80+
3. **Serial Number**: Search by certificate serial number (hex format)
81+
- Example: `03f7b3b2a8c9d1e2f4a5b6c7d8e9f0a1`
82+
83+
4. **SHA-256**: Search by certificate SHA-256 fingerprint
84+
- Example: `a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456`
85+
86+
5. **Issuer**: Search by certificate issuer Common Name
87+
- Example: `Let's Encrypt Authority X3`
88+
89+
## Project Structure
90+
91+
```
92+
ui/
93+
├── app/
94+
│ ├── api/
95+
│ │ ├── search/route.ts # Search API endpoint
96+
│ │ └── certificate/[sha256]/route.ts # Certificate detail API
97+
│ ├── certificate/[sha256]/page.tsx # Certificate detail page
98+
│ ├── layout.tsx # Root layout
99+
│ ├── page.tsx # Main search page
100+
│ └── globals.css # Global styles
101+
├── components/
102+
│ ├── search-form.tsx # Search interface
103+
│ └── certificate-list.tsx # Certificate results list
104+
├── lib/
105+
│ └── clickhouse.ts # ClickHouse client configuration
106+
├── types/
107+
│ └── certificate.ts # TypeScript interfaces
108+
└── public/ # Static assets
109+
```
110+
111+
## Development
112+
113+
- `npm run dev` - Start development server
114+
- `npm run build` - Build for production
115+
- `npm run start` - Start production server
116+
- `npm run lint` - Run ESLint
117+
118+
## Contributing
119+
120+
1. Fork the repository
121+
2. Create a feature branch
122+
3. Make your changes
123+
4. Run linting and tests
124+
5. Submit a pull request
125+
126+
## License
127+
128+
See the main project LICENSE file.

0 commit comments

Comments
 (0)