mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-19 02:27:03 +00:00
Compare commits
56 Commits
v3.0.0-rc1
...
v3.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a10a6244c9 | ||
|
|
9185423022 | ||
|
|
9aaca449f8 | ||
|
|
f39395bd7f | ||
|
|
2c68128d5d | ||
|
|
06d4120682 | ||
|
|
58bcd4f557 | ||
|
|
e91e8d5aee | ||
|
|
5322462899 | ||
|
|
5def9ed183 | ||
|
|
357589d90e | ||
|
|
b664bcfc4c | ||
|
|
ffd13e2ee7 | ||
|
|
747775b8f2 | ||
|
|
2c0d942c76 | ||
|
|
e7263439d5 | ||
|
|
cb6f99c487 | ||
|
|
04fb58e15e | ||
|
|
f11ad55474 | ||
|
|
26939f2bf6 | ||
|
|
05a3b1742a | ||
|
|
867d5f5d7f | ||
|
|
8e34a21dc6 | ||
|
|
8869acef0b | ||
|
|
752d5c9668 | ||
|
|
091e26c467 | ||
|
|
6593a36b48 | ||
|
|
68ef2d9873 | ||
|
|
ab988caf6b | ||
|
|
fa62220d98 | ||
|
|
1ecf424975 | ||
|
|
3342938dd4 | ||
|
|
6be1655723 | ||
|
|
1465e6fb49 | ||
|
|
21991cbfc7 | ||
|
|
7138a97935 | ||
|
|
beee68fc5d | ||
|
|
9e2af71743 | ||
|
|
a2c4292fc1 | ||
|
|
2016142747 | ||
|
|
4f9f961cac | ||
|
|
bf8536abb3 | ||
|
|
985f2702f2 | ||
|
|
11f3879442 | ||
|
|
8562c55c98 | ||
|
|
e3066bb535 | ||
|
|
35ab31efbc | ||
|
|
81edf40996 | ||
|
|
c64e7a6a6c | ||
|
|
4bd64563f2 | ||
|
|
66dec49a49 | ||
|
|
649e3743e0 | ||
|
|
c096f018d6 | ||
|
|
261bbef426 | ||
|
|
3c5960aba0 | ||
|
|
7f430f2bde |
36
.github/workflows/build-and-test.yml
vendored
Normal file
36
.github/workflows/build-and-test.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
name: Build and Test
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
jobs:
|
||||||
|
go-build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go: [ '1.17', '1.16' ]
|
||||||
|
name: Go ${{ matrix.go }} build
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go }}
|
||||||
|
- name: Build and test
|
||||||
|
run: |
|
||||||
|
go build ./...
|
||||||
|
go test -race -coverprofile=profile.cov ./...
|
||||||
|
- name: Send coverage
|
||||||
|
uses: shogo82148/actions-goveralls@v1
|
||||||
|
with:
|
||||||
|
path-to-profile: profile.cov
|
||||||
|
flag-name: Go-${{ matrix.go }}
|
||||||
|
parallel: true
|
||||||
|
coverage:
|
||||||
|
needs: go-build
|
||||||
|
name: Test Coverage
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: shogo82148/actions-goveralls@v1
|
||||||
|
with:
|
||||||
|
parallel-finished: true
|
||||||
51
.github/workflows/docker-build.yml
vendored
51
.github/workflows/docker-build.yml
vendored
@@ -1,15 +1,54 @@
|
|||||||
name: Docker Image
|
name: Docker Image
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "master", "develop" ]
|
branches: [ "main" ]
|
||||||
|
tags: [ "v*" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Checkout
|
||||||
- uses: docker/build-push-action@v1
|
uses: actions/checkout@v2
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v3
|
||||||
with:
|
with:
|
||||||
repository: inbucket/inbucket
|
images: |
|
||||||
push: false
|
inbucket/inbucket
|
||||||
tag_with_ref: true
|
ghcr.io/${{ github.repository }}
|
||||||
|
tags: |
|
||||||
|
type=ref,event=branch
|
||||||
|
type=ref,event=pr
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=sha
|
||||||
|
type=edge,branch=main
|
||||||
|
flavor: |
|
||||||
|
latest=auto
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
- name: Login to DockerHub
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64, linux/arm/v7
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|||||||
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
name: Build and Release
|
name: Build and Release
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "master", "develop" ]
|
branches: [ "main" ]
|
||||||
tags: [ "v*" ]
|
tags: [ "v*" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
jobs:
|
jobs:
|
||||||
@@ -14,19 +14,17 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.15
|
go-version: 1.17
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '10.x'
|
node-version: '16.x'
|
||||||
- name: Setup Elm
|
cache: 'yarn'
|
||||||
uses: jorelali/setup-elm@v2
|
cache-dependency-path: ui/yarn.lock
|
||||||
with:
|
|
||||||
elm-version: 0.19.1
|
|
||||||
- name: Build frontend
|
- name: Build frontend
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
yarn install --frozen-lockfile --non-interactive
|
||||||
npm run build
|
yarn run build
|
||||||
working-directory: ./ui
|
working-directory: ./ui
|
||||||
- name: Test build release
|
- name: Test build release
|
||||||
uses: goreleaser/goreleaser-action@v2
|
uses: goreleaser/goreleaser-action@v2
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -52,3 +52,4 @@ repl-temp-*
|
|||||||
/ui/dist/
|
/ui/dist/
|
||||||
# Dependency directories
|
# Dependency directories
|
||||||
/ui/node_modules
|
/ui/node_modules
|
||||||
|
/ui/.parcel-cache
|
||||||
|
|||||||
@@ -6,12 +6,6 @@ release:
|
|||||||
name: inbucket
|
name: inbucket
|
||||||
name_template: '{{.Tag}}'
|
name_template: '{{.Tag}}'
|
||||||
|
|
||||||
brews:
|
|
||||||
- commit_author:
|
|
||||||
name: goreleaserbot
|
|
||||||
email: goreleaser@carlosbecker.com
|
|
||||||
install: bin.install ""
|
|
||||||
|
|
||||||
before:
|
before:
|
||||||
hooks:
|
hooks:
|
||||||
- go mod download
|
- go mod download
|
||||||
@@ -28,8 +22,10 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- amd64
|
||||||
|
- arm
|
||||||
|
- arm64
|
||||||
goarm:
|
goarm:
|
||||||
- "6"
|
- "7"
|
||||||
main: ./cmd/inbucket
|
main: ./cmd/inbucket
|
||||||
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
|
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
|
||||||
- id: inbucket-client
|
- id: inbucket-client
|
||||||
@@ -43,8 +39,10 @@ builds:
|
|||||||
- windows
|
- windows
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- amd64
|
||||||
|
- arm
|
||||||
|
- arm64
|
||||||
goarm:
|
goarm:
|
||||||
- "6"
|
- "7"
|
||||||
main: ./cmd/client
|
main: ./cmd/client
|
||||||
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
|
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
|
||||||
|
|
||||||
@@ -61,8 +59,8 @@ archives:
|
|||||||
- LICENSE*
|
- LICENSE*
|
||||||
- README*
|
- README*
|
||||||
- CHANGELOG*
|
- CHANGELOG*
|
||||||
- etc/**/*
|
- etc/**
|
||||||
- ui/dist/**/*
|
- ui/dist/**
|
||||||
- ui/greeting.html
|
- ui/greeting.html
|
||||||
|
|
||||||
nfpms:
|
nfpms:
|
||||||
@@ -74,11 +72,15 @@ nfpms:
|
|||||||
maintainer: github@hillyerd.com
|
maintainer: github@hillyerd.com
|
||||||
description: All-in-one disposable webmail service.
|
description: All-in-one disposable webmail service.
|
||||||
license: MIT
|
license: MIT
|
||||||
files:
|
contents:
|
||||||
"ui/dist/**/*": "/usr/local/share/inbucket/ui"
|
- src: "ui/dist/**"
|
||||||
config_files:
|
dst: "/usr/local/share/inbucket/ui"
|
||||||
"etc/linux/inbucket.service": "/lib/systemd/system/inbucket.service"
|
- src: "etc/linux/inbucket.service"
|
||||||
"ui/greeting.html": "/etc/inbucket/greeting.html"
|
dst: "/lib/systemd/system/inbucket.service"
|
||||||
|
type: config|noreplace
|
||||||
|
- src: "ui/greeting.html"
|
||||||
|
dst: "/etc/inbucket/greeting.html"
|
||||||
|
type: config|noreplace
|
||||||
|
|
||||||
snapshot:
|
snapshot:
|
||||||
name_template: SNAPSHOT-{{ .Commit }}
|
name_template: SNAPSHOT-{{ .Commit }}
|
||||||
|
|||||||
30
.travis.yml
30
.travis.yml
@@ -1,30 +0,0 @@
|
|||||||
dist: bionic
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- GO111MODULE=on
|
|
||||||
|
|
||||||
language: go
|
|
||||||
|
|
||||||
install:
|
|
||||||
- "go get golang.org/x/lint/golint"
|
|
||||||
- "make deps"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
include:
|
|
||||||
- go: "1.14.x"
|
|
||||||
- go: "1.15.x"
|
|
||||||
- language: elm
|
|
||||||
elm: "latest-0.19.1"
|
|
||||||
elm_format: "latest-0.19.1"
|
|
||||||
elm_test: "latest-0.19.1"
|
|
||||||
node_js: "10.16.0"
|
|
||||||
install:
|
|
||||||
- "cd ui"
|
|
||||||
- "npm ci"
|
|
||||||
script:
|
|
||||||
- "elm-format --validate ."
|
|
||||||
- "npm run build"
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- test
|
|
||||||
120
CHANGELOG.md
120
CHANGELOG.md
@@ -4,7 +4,71 @@ Change Log
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
## [v3.0.0-rc1]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [v3.0.2] - 2022-07-04
|
||||||
|
|
||||||
|
Note: We had to abandon the 3.0.1 release, see the blog post [What happened to
|
||||||
|
3.0?](https://www.inbucket.org/news/2022/05/whathappenedtothree.html) for
|
||||||
|
details.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- arm Docker builds now rely on amd64 frontend build stage
|
||||||
|
- Frontend build migrated from npm+webpack to yarn+parcel, node 16
|
||||||
|
|
||||||
|
|
||||||
|
## [v3.0.1-rc2] - 2022-01-23
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Builds for arm7 and arm64 platforms
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Abandoned git-flow process, the `master` branch renamed to `main`
|
||||||
|
|
||||||
|
|
||||||
|
## [v3.0.1-rc1] - 2022-01-17
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- GitHub built packages (rpm, deb, tarball) no longer missing UI files (#250)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Update Go dependencies
|
||||||
|
- Update NPM dependencies
|
||||||
|
|
||||||
|
|
||||||
|
## [v3.0.0] - 2021-09-19
|
||||||
|
|
||||||
|
Unchanged from rc4.
|
||||||
|
|
||||||
|
|
||||||
|
## [v3.0.0-rc4] - 2021-08-22
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Various MIME header decoding improvements
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Bump Go version to 1.17 (#233)
|
||||||
|
|
||||||
|
|
||||||
|
## v3.0.0-rc3 - 2021-08-01
|
||||||
|
|
||||||
|
Unchanaged from 3.0.0-rc2. This release is to update our build automation and
|
||||||
|
tags for Docker Hub and ghcr.io.
|
||||||
|
|
||||||
|
|
||||||
|
## [v3.0.0-rc2] - 2021-07-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Support for SMTP AUTH (#197, thanks makarchuk)
|
||||||
|
- Dark mode support (#218, thanks nerones)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Prevent potential click jacking (#190, thanks stuartskelton)
|
||||||
|
- Error on 8 character long SMTP commands (#221)
|
||||||
|
- Allow empty username and password during AUTH (#225)
|
||||||
|
|
||||||
|
|
||||||
|
## [v3.0.0-rc1] - 2020-09-24
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Refresh button to reload mailbox contents
|
- Refresh button to reload mailbox contents
|
||||||
@@ -15,7 +79,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
fonts
|
fonts
|
||||||
|
|
||||||
|
|
||||||
## [v3.0.0-beta3]
|
## [v3.0.0-beta3] - 2020-09-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Docker `HEALTHCHECK`
|
- Docker `HEALTHCHECK`
|
||||||
@@ -31,7 +95,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- Allow empty SMTP `MAIL FROM:<>`
|
- Allow empty SMTP `MAIL FROM:<>`
|
||||||
|
|
||||||
|
|
||||||
## [v3.0.0-beta2]
|
## [v3.0.0-beta2] - 2019-08-17
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Ability to name mailboxes after domain of email recipient, set via
|
- Ability to name mailboxes after domain of email recipient, set via
|
||||||
@@ -47,7 +111,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- Support for late EHLO, #141
|
- Support for late EHLO, #141
|
||||||
|
|
||||||
|
|
||||||
## [v3.0.0-beta1]
|
## [v3.0.0-beta1] - 2019-03-14
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- `posix-millis` field to REST message and header responses for easier date
|
- `posix-millis` field to REST message and header responses for easier date
|
||||||
@@ -60,12 +124,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- Update to enmime v0.5.0
|
- Update to enmime v0.5.0
|
||||||
|
|
||||||
|
|
||||||
## v2.1.0
|
## v2.1.0 - 2018-12-15
|
||||||
|
|
||||||
No change from beta1.
|
No change from beta1.
|
||||||
|
|
||||||
|
|
||||||
## [v2.1.0-beta1]
|
## [v2.1.0-beta1] - 2018-10-31
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Use Go 1.11 modules for reproducible builds.
|
- Use Go 1.11 modules for reproducible builds.
|
||||||
@@ -238,37 +302,45 @@ No change from beta1.
|
|||||||
- Add Link button to messages, allows for directing another person to a
|
- Add Link button to messages, allows for directing another person to a
|
||||||
specific message.
|
specific message.
|
||||||
|
|
||||||
[Unreleased]: https://github.com/inbucket/inbucket/compare/master...develop
|
|
||||||
[v3.0.0-rc1]: https://github.com/inbucket/inbucket/compare/v3.0.0-beta3...v3.0.0-rc1
|
[Unreleased]: https://github.com/inbucket/inbucket/compare/v3.0.2...main
|
||||||
|
[v3.0.2]: https://github.com/inbucket/inbucket/compare/v3.0.1-rc2...v3.0.2
|
||||||
|
[v3.0.1-rc2]: https://github.com/inbucket/inbucket/compare/v3.0.1-rc1...v3.0.1-rc2
|
||||||
|
[v3.0.1-rc1]: https://github.com/inbucket/inbucket/compare/v3.0.0...v3.0.1-rc1
|
||||||
|
[v3.0.0]: https://github.com/inbucket/inbucket/compare/v3.0.0-rc4...v3.0.0
|
||||||
|
[v3.0.0-rc4]: https://github.com/inbucket/inbucket/compare/v3.0.0-rc2...v3.0.0-rc4
|
||||||
|
[v3.0.0-rc2]: https://github.com/inbucket/inbucket/compare/v3.0.0-rc1...v3.0.0-rc2
|
||||||
|
[v3.0.0-rc1]: https://github.com/inbucket/inbucket/compare/v3.0.0-beta3...v3.0.0-rc1
|
||||||
[v3.0.0-beta3]: https://github.com/inbucket/inbucket/compare/v3.0.0-beta2...v3.0.0-beta3
|
[v3.0.0-beta3]: https://github.com/inbucket/inbucket/compare/v3.0.0-beta2...v3.0.0-beta3
|
||||||
[v3.0.0-beta2]: https://github.com/inbucket/inbucket/compare/v3.0.0-beta1...v3.0.0-beta2
|
[v3.0.0-beta2]: https://github.com/inbucket/inbucket/compare/v3.0.0-beta1...v3.0.0-beta2
|
||||||
[v3.0.0-beta1]: https://github.com/inbucket/inbucket/compare/v2.1.0...v3.0.0-beta1
|
[v3.0.0-beta1]: https://github.com/inbucket/inbucket/compare/v2.1.0...v3.0.0-beta1
|
||||||
[v2.1.0-beta1]: https://github.com/inbucket/inbucket/compare/v2.0.0...v2.1.0-beta1
|
[v2.1.0-beta1]: https://github.com/inbucket/inbucket/compare/v2.0.0...v2.1.0-beta1
|
||||||
[v2.0.0]: https://github.com/inbucket/inbucket/compare/v2.0.0-rc1...v2.0.0
|
[v2.0.0]: https://github.com/inbucket/inbucket/compare/v2.0.0-rc1...v2.0.0
|
||||||
[v2.0.0-rc1]: https://github.com/inbucket/inbucket/compare/v1.3.1...v2.0.0-rc1
|
[v2.0.0-rc1]: https://github.com/inbucket/inbucket/compare/v1.3.1...v2.0.0-rc1
|
||||||
[v1.3.1]: https://github.com/inbucket/inbucket/compare/v1.3.0...v1.3.1
|
[v1.3.1]: https://github.com/inbucket/inbucket/compare/v1.3.0...v1.3.1
|
||||||
[v1.3.0]: https://github.com/inbucket/inbucket/compare/v1.2.0...v1.3.0
|
[v1.3.0]: https://github.com/inbucket/inbucket/compare/v1.2.0...v1.3.0
|
||||||
[v1.2.0]: https://github.com/inbucket/inbucket/compare/1.2.0-rc2...1.2.0
|
[v1.2.0]: https://github.com/inbucket/inbucket/compare/1.2.0-rc2...1.2.0
|
||||||
[v1.2.0-rc2]: https://github.com/inbucket/inbucket/compare/1.2.0-rc1...1.2.0-rc2
|
[v1.2.0-rc2]: https://github.com/inbucket/inbucket/compare/1.2.0-rc1...1.2.0-rc2
|
||||||
[v1.2.0-rc1]: https://github.com/inbucket/inbucket/compare/1.1.0...1.2.0-rc1
|
[v1.2.0-rc1]: https://github.com/inbucket/inbucket/compare/1.1.0...1.2.0-rc1
|
||||||
[v1.1.0]: https://github.com/inbucket/inbucket/compare/1.1.0-rc2...1.1.0
|
[v1.1.0]: https://github.com/inbucket/inbucket/compare/1.1.0-rc2...1.1.0
|
||||||
[v1.1.0-rc2]: https://github.com/inbucket/inbucket/compare/1.1.0-rc1...1.1.0-rc2
|
[v1.1.0-rc2]: https://github.com/inbucket/inbucket/compare/1.1.0-rc1...1.1.0-rc2
|
||||||
[v1.1.0-rc1]: https://github.com/inbucket/inbucket/compare/1.0...1.1.0-rc1
|
[v1.1.0-rc1]: https://github.com/inbucket/inbucket/compare/1.0...1.1.0-rc1
|
||||||
[v1.0]: https://github.com/inbucket/inbucket/compare/1.0-rc1...1.0
|
[v1.0]: https://github.com/inbucket/inbucket/compare/1.0-rc1...1.0
|
||||||
|
|
||||||
|
|
||||||
## Release Checklist
|
## Release Checklist
|
||||||
|
|
||||||
1. Create release branch: `git flow release start 1.x.0`
|
1. Create a release branch
|
||||||
2. Update CHANGELOG.md:
|
2. Update CHANGELOG.md:
|
||||||
- Ensure *Unreleased* section is up to date
|
- Ensure *Unreleased* section is up to date
|
||||||
- Rename *Unreleased* section to release name and date.
|
- Rename *Unreleased* section to release name and date
|
||||||
- Add new GitHub `/compare` link
|
- Add new GitHub `/compare` link
|
||||||
|
- Update previous tag version for *Unreleased*
|
||||||
3. Run tests
|
3. Run tests
|
||||||
4. Update goreleaser, and then test cross-compile: `goreleaser --snapshot`
|
4. Update goreleaser, and then test cross-compile: `goreleaser --snapshot`
|
||||||
5. Commit changes and merge release: `git flow release finish`
|
5. Commit changes and merge release into main, tag `vX.Y.Z`
|
||||||
6. Push tags and wait for https://travis-ci.org/inbucket/inbucket build to
|
6. Push tags and wait for
|
||||||
complete
|
[GitHub actions](https://github.com/inbucket/inbucket/actions) to complete
|
||||||
7. Update `binary_versions` option in `inbucket-site/_config.yml`
|
7. Update `binary_versions` option in `inbucket-site/_config.yml`
|
||||||
|
|
||||||
See http://keepachangelog.com/ for additional instructions on how to update this file.
|
See http://keepachangelog.com/ for additional instructions on how to update this file.
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
How to Contribute
|
# How to Contribute
|
||||||
=================
|
|
||||||
|
|
||||||
Inbucket encourages third-party patches. It's valuable to know how other
|
Inbucket encourages third-party patches. It's valuable to know how other
|
||||||
developers are using the product.
|
developers are using the product.
|
||||||
|
|
||||||
**tl;dr:** File pull requests against the `develop` branch, not `master`!
|
|
||||||
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
@@ -17,28 +14,18 @@ to provide validation and/or guidance on your suggested approach.
|
|||||||
|
|
||||||
## Making Changes
|
## Making Changes
|
||||||
|
|
||||||
Inbucket uses [git-flow] with default options. If you have git-flow installed,
|
Inbucket follows the regular GitHub pattern. Create a topic branch from where
|
||||||
you can run `git flow feature start <topic branch name>`.
|
you want to base your work:
|
||||||
|
|
||||||
Without git-flow, create a topic branch from where you want to base your work:
|
|
||||||
- This is usually the `develop` branch, example command:
|
|
||||||
`git checkout origin/develop -b <topic branch name>`
|
|
||||||
- Only target the `master` branch if the issue is already resolved in
|
|
||||||
`develop`.
|
|
||||||
|
|
||||||
Once you are on your topic branch:
|
Once you are on your topic branch:
|
||||||
|
|
||||||
1. Make commits of logical units.
|
1. Make commits of logical units.
|
||||||
2. Add unit tests to exercise your changes.
|
2. Add unit tests to exercise your changes.
|
||||||
3. Run the updated code through `go fmt` and `go vet`.
|
3. Run `make` to test, vet and confirm your code is formatted correctly.
|
||||||
4. Ensure the code builds and tests with the following commands:
|
If you do not have Make installed, please perform these steps manually,
|
||||||
- `go clean ./...`
|
otherwise your PR will not pass our checks.
|
||||||
- `go build ./...`
|
|
||||||
- `go test ./...`
|
|
||||||
|
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
||||||
Thank you for contributing to Inbucket!
|
Thank you for contributing to Inbucket!
|
||||||
|
|
||||||
[git-flow]: https://github.com/nvie/gitflow
|
|
||||||
|
|||||||
36
Dockerfile
36
Dockerfile
@@ -1,35 +1,33 @@
|
|||||||
# Docker build file for Inbucket: https://www.inbucket.org/
|
# Docker build file for Inbucket: https://www.inbucket.org/
|
||||||
|
|
||||||
# Install build-time dependencies
|
### Build frontend
|
||||||
FROM golang:1.15-alpine3.12 as builder
|
# Due to no official elm compiler for arm; build frontend with amd64.
|
||||||
RUN apk add --no-cache --virtual .build-deps g++ git make npm python3
|
FROM --platform=linux/amd64 node:16 as frontend
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . .
|
||||||
|
WORKDIR /build/ui
|
||||||
|
RUN rm -rf .parcel-cache dist elm-stuff node_modules
|
||||||
|
RUN yarn install --frozen-lockfile --non-interactive
|
||||||
|
RUN yarn run build
|
||||||
|
|
||||||
|
### Build backend
|
||||||
|
FROM golang:1.17-alpine3.14 as backend
|
||||||
|
RUN apk add --no-cache --virtual .build-deps g++ git make
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
COPY . .
|
COPY . .
|
||||||
ENV CGO_ENABLED 0
|
ENV CGO_ENABLED 0
|
||||||
RUN make clean deps
|
RUN make clean deps
|
||||||
WORKDIR /build/ui
|
|
||||||
RUN rm -rf dist elm-stuff node_modules
|
|
||||||
RUN npm ci
|
|
||||||
ADD https://github.com/elm/compiler/releases/download/0.19.1/binary-for-linux-64-bit.gz elm.gz
|
|
||||||
RUN gunzip elm.gz && chmod 755 elm && mv elm /usr/bin/
|
|
||||||
|
|
||||||
# Build server
|
|
||||||
WORKDIR /build
|
|
||||||
RUN go build -o inbucket \
|
RUN go build -o inbucket \
|
||||||
-ldflags "-X 'main.version=$(git describe --tags --always)' -X 'main.date=$(date -Iseconds)'" \
|
-ldflags "-X 'main.version=$(git describe --tags --always)' -X 'main.date=$(date -Iseconds)'" \
|
||||||
-v ./cmd/inbucket
|
-v ./cmd/inbucket
|
||||||
|
|
||||||
# Build frontend
|
### Run in minimal image
|
||||||
WORKDIR /build/ui
|
FROM alpine:3.14
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# Run in minimal image
|
|
||||||
FROM alpine:3.12
|
|
||||||
RUN apk --no-cache add tzdata
|
RUN apk --no-cache add tzdata
|
||||||
WORKDIR /opt/inbucket
|
WORKDIR /opt/inbucket
|
||||||
RUN mkdir bin defaults ui
|
RUN mkdir bin defaults ui
|
||||||
COPY --from=builder /build/inbucket bin
|
COPY --from=backend /build/inbucket bin
|
||||||
COPY --from=builder /build/ui/dist ui
|
COPY --from=frontend /build/ui/dist ui
|
||||||
COPY etc/docker/defaults/greeting.html defaults
|
COPY etc/docker/defaults/greeting.html defaults
|
||||||
COPY etc/docker/defaults/start-inbucket.sh /
|
COPY etc/docker/defaults/start-inbucket.sh /
|
||||||
|
|
||||||
|
|||||||
24
README.md
24
README.md
@@ -1,7 +1,7 @@
|
|||||||
Inbucket
|

|
||||||
=============================================================================
|

|
||||||
[][Build Status]
|
|
||||||
[][Docker Image]
|
# Inbucket
|
||||||
|
|
||||||
Inbucket is an email testing service; it will accept messages for any email
|
Inbucket is an email testing service; it will accept messages for any email
|
||||||
address and make them available via web, REST and POP3 interfaces. Once
|
address and make them available via web, REST and POP3 interfaces. Once
|
||||||
@@ -26,9 +26,9 @@ to contribute code to the project check out [CONTRIBUTING.md].
|
|||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
Inbucket has automated [Docker Image] builds via Docker Hub. The `stable` tag
|
Inbucket has automated [Docker Image] builds via Docker Hub. The `latest` tag
|
||||||
tracks our `master` branch (releases), `latest` tracks our unstable
|
tracks our tagged releases, and `edge` tracks our potentially unstable
|
||||||
`development` branch.
|
`main` branch.
|
||||||
|
|
||||||
|
|
||||||
## Building from Source
|
## Building from Source
|
||||||
@@ -38,8 +38,8 @@ You will need functioning [Go] and [Node.js] installations for this to work.
|
|||||||
```sh
|
```sh
|
||||||
git clone https://github.com/inbucket/inbucket.git
|
git clone https://github.com/inbucket/inbucket.git
|
||||||
cd inbucket/ui
|
cd inbucket/ui
|
||||||
npm ci
|
yarn install
|
||||||
npm run build
|
yarn build
|
||||||
cd ..
|
cd ..
|
||||||
go build ./cmd/inbucket
|
go build ./cmd/inbucket
|
||||||
```
|
```
|
||||||
@@ -72,10 +72,10 @@ Inbucket is open source software released under the MIT License. The latest
|
|||||||
version can be found at https://github.com/inbucket/inbucket
|
version can be found at https://github.com/inbucket/inbucket
|
||||||
|
|
||||||
[Build Status]: https://travis-ci.org/inbucket/inbucket
|
[Build Status]: https://travis-ci.org/inbucket/inbucket
|
||||||
[Change Log]: https://github.com/inbucket/inbucket/blob/master/CHANGELOG.md
|
[Change Log]: https://github.com/inbucket/inbucket/blob/main/CHANGELOG.md
|
||||||
[config.md]: https://github.com/inbucket/inbucket/blob/master/doc/config.md
|
[config.md]: https://github.com/inbucket/inbucket/blob/main/doc/config.md
|
||||||
[Configurator]: https://www.inbucket.org/configurator/
|
[Configurator]: https://www.inbucket.org/configurator/
|
||||||
[CONTRIBUTING.md]: https://github.com/inbucket/inbucket/blob/develop/CONTRIBUTING.md
|
[CONTRIBUTING.md]: https://github.com/inbucket/inbucket/blob/main/CONTRIBUTING.md
|
||||||
[Development Quickstart]: https://github.com/inbucket/inbucket/wiki/Development-Quickstart
|
[Development Quickstart]: https://github.com/inbucket/inbucket/wiki/Development-Quickstart
|
||||||
[Docker Image]: https://www.inbucket.org/binaries/docker.html
|
[Docker Image]: https://www.inbucket.org/binaries/docker.html
|
||||||
[Elm]: https://elm-lang.org/
|
[Elm]: https://elm-lang.org/
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ case "$1" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
export SWAKS_OPT_server="127.0.0.1:2500"
|
export SWAKS_OPT_server="${SWAKS_OPT_server:-127.0.0.1:2500}"
|
||||||
export SWAKS_OPT_to="$to@inbucket.local"
|
export SWAKS_OPT_to="$to@inbucket.local"
|
||||||
|
|
||||||
# Basic test
|
# Basic test
|
||||||
|
|||||||
22
go.mod
22
go.mod
@@ -2,24 +2,22 @@ module github.com/inbucket/inbucket
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 // indirect
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
|
||||||
github.com/google/subcommands v1.2.0
|
github.com/google/subcommands v1.2.0
|
||||||
github.com/gorilla/css v1.0.0
|
github.com/gorilla/css v1.0.0
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 // indirect
|
github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba // indirect
|
||||||
github.com/jhillyerd/enmime v0.8.1
|
github.com/jhillyerd/enmime v0.9.2
|
||||||
github.com/jhillyerd/goldiff v0.1.0
|
github.com/jhillyerd/goldiff v0.1.0
|
||||||
github.com/kelseyhightower/envconfig v1.4.0
|
github.com/kelseyhightower/envconfig v1.4.0
|
||||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||||
github.com/microcosm-cc/bluemonday v1.0.4
|
github.com/microcosm-cc/bluemonday v1.0.17
|
||||||
github.com/olekukonko/tablewriter v0.0.4 // indirect
|
github.com/rs/zerolog v1.26.1
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/rs/zerolog v1.20.0
|
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d
|
||||||
github.com/stretchr/testify v1.6.1
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/net v0.0.0-20200923182212-328152dc79b1
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
golang.org/x/text v0.3.3 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|||||||
96
go.sum
96
go.sum
@@ -2,18 +2,16 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP
|
|||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI=
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI=
|
||||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8=
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8=
|
||||||
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
|
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw=
|
github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
|
||||||
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
|
||||||
github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561 h1:aBzukfDxQlCTVS0NBUjI5YA3iVeaZ9Tb5PxNrrIP1xs=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
|
||||||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 h1:gBeyun7mySAKWg7Fb0GOcv0upX9bdaZScs8QcRo8mEY=
|
|
||||||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||||
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
|
||||||
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||||
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||||
@@ -22,68 +20,72 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
|||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43 h1:jTkyeF7NZ5oIr0ESmcrpiDgAfoidCBF4F5kJhjtaRwE=
|
|
||||||
github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
|
||||||
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 h1:g0fAGBisHaEQ0TRq1iBvemFRf+8AEWEmBESSiWB3Vsc=
|
|
||||||
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
||||||
github.com/jhillyerd/enmime v0.8.1 h1:Kz4xj3sJJ4Ju8e+w/7v9H4Matv5ijPgv7UkhPf+C15I=
|
github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba h1:QFQpJdgbON7I0jr2hYW7Bs+XV0qjc3d5tZoDnRFnqTg=
|
||||||
github.com/jhillyerd/enmime v0.8.1/go.mod h1:MBHs3ugk03NGjMM6PuRynlKf+HA5eSillZ+TRCm73AE=
|
github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
||||||
|
github.com/jhillyerd/enmime v0.9.2 h1:Njvy7yubcX21WaM+kWdVxGFJ99Rk6xHqgon3Ep++qDw=
|
||||||
|
github.com/jhillyerd/enmime v0.9.2/go.mod h1:S5ge4lnv/dDDBbAWwtoOFlj14NHiXdw/EqMB2lJz3b8=
|
||||||
github.com/jhillyerd/goldiff v0.1.0 h1:7JzKPKVwAg1GzrbnsToYzq3Y5+S7dXM4hgEYiOzaf4A=
|
github.com/jhillyerd/goldiff v0.1.0 h1:7JzKPKVwAg1GzrbnsToYzq3Y5+S7dXM4hgEYiOzaf4A=
|
||||||
github.com/jhillyerd/goldiff v0.1.0/go.mod h1:WeDal6DTqhbMhNkf5REzWCIvKl3JWs0Q9omZ/huIWAs=
|
github.com/jhillyerd/goldiff v0.1.0/go.mod h1:WeDal6DTqhbMhNkf5REzWCIvKl3JWs0Q9omZ/huIWAs=
|
||||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
|
||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
|
||||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.4 h1:p0L+CTpo/PLFdkoPcJemLXG+fpMD7pYOoDEq1axMbGg=
|
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.4/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
|
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||||
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
|
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
github.com/microcosm-cc/bluemonday v1.0.17 h1:Z1a//hgsQ4yjC+8zEkV8IWySkXnsxmdSY642CTFQb5Y=
|
||||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
github.com/microcosm-cc/bluemonday v1.0.17/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM=
|
||||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=
|
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
|
||||||
|
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20210501142056-aec3718b3fa0/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
golang.org/x/net v0.0.0-20200923182212-328152dc79b1 h1:Iu68XRPd67wN4aRGGWwwq6bZo/25jR6uu52l/j2KkUE=
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20200923182212-328152dc79b1/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs=
|
||||||
|
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
@@ -25,10 +25,27 @@ const (
|
|||||||
// timeStampFormat to use in Received header.
|
// timeStampFormat to use in Received header.
|
||||||
timeStampFormat = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)"
|
timeStampFormat = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)"
|
||||||
|
|
||||||
|
// Messages sent to user during LOGIN auth procedure. Can vary, but values are taken directly
|
||||||
|
// from spec https://tools.ietf.org/html/draft-murchison-sasl-login-00
|
||||||
|
|
||||||
|
// usernameChallenge sent when inviting user to provide username. Is base64 encoded string
|
||||||
|
// `User Name`
|
||||||
|
usernameChallenge = "VXNlciBOYW1lAA=="
|
||||||
|
|
||||||
|
// passwordChallenge sent when inviting user to provide password. Is base64 encoded string
|
||||||
|
// `Password`
|
||||||
|
passwordChallenge = "UGFzc3dvcmQA"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
// GREET State: Waiting for HELO
|
// GREET State: Waiting for HELO
|
||||||
GREET State = iota
|
GREET State = iota
|
||||||
// READY State: Got HELO, waiting for MAIL
|
// READY State: Got HELO, waiting for MAIL
|
||||||
READY
|
READY
|
||||||
|
// LOGIN State: Got AUTH LOGIN command, expecting Username
|
||||||
|
LOGIN
|
||||||
|
// PASSWORD State: Got Username, expecting password
|
||||||
|
PASSWORD
|
||||||
// MAIL State: Got MAIL, accepting RCPTs
|
// MAIL State: Got MAIL, accepting RCPTs
|
||||||
MAIL
|
MAIL
|
||||||
// DATA State: Got DATA, waiting for "."
|
// DATA State: Got DATA, waiting for "."
|
||||||
@@ -76,6 +93,7 @@ var commands = map[string]bool{
|
|||||||
"QUIT": true,
|
"QUIT": true,
|
||||||
"TURN": true,
|
"TURN": true,
|
||||||
"STARTTLS": true,
|
"STARTTLS": true,
|
||||||
|
"AUTH": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session holds the state of an SMTP session
|
// Session holds the state of an SMTP session
|
||||||
@@ -153,6 +171,16 @@ func (s *Server) startSession(id int, conn net.Conn) {
|
|||||||
}
|
}
|
||||||
line, err := ssn.readLine()
|
line, err := ssn.readLine()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
//Handle LOGIN/PASSWORD states here, because they don't expect a command
|
||||||
|
switch ssn.state {
|
||||||
|
case LOGIN:
|
||||||
|
ssn.loginHandler(line)
|
||||||
|
continue
|
||||||
|
case PASSWORD:
|
||||||
|
ssn.passwordHandler(line)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if cmd, arg, ok := ssn.parseCmd(line); ok {
|
if cmd, arg, ok := ssn.parseCmd(line); ok {
|
||||||
// Check against valid SMTP commands
|
// Check against valid SMTP commands
|
||||||
if cmd == "" {
|
if cmd == "" {
|
||||||
@@ -219,7 +247,7 @@ func (s *Server) startSession(id int, conn net.Conn) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// not an EOF
|
// Not an EOF
|
||||||
ssn.logger.Warn().Msgf("Connection error: %v", err)
|
ssn.logger.Warn().Msgf("Connection error: %v", err)
|
||||||
if netErr, ok := err.(net.Error); ok {
|
if netErr, ok := err.(net.Error); ok {
|
||||||
if netErr.Timeout() {
|
if netErr.Timeout() {
|
||||||
@@ -257,9 +285,10 @@ func (s *Session) greetHandler(cmd string, arg string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.remoteDomain = domain
|
s.remoteDomain = domain
|
||||||
// features before SIZE per RFC
|
// Features before SIZE per RFC
|
||||||
s.send("250-" + readyBanner)
|
s.send("250-" + readyBanner)
|
||||||
s.send("250-8BITMIME")
|
s.send("250-8BITMIME")
|
||||||
|
s.send("250-AUTH PLAIN LOGIN")
|
||||||
if s.Server.config.TLSEnabled && s.Server.tlsConfig != nil && s.tlsState == nil {
|
if s.Server.config.TLSEnabled && s.Server.tlsConfig != nil && s.tlsState == nil {
|
||||||
s.send("250-STARTTLS")
|
s.send("250-STARTTLS")
|
||||||
}
|
}
|
||||||
@@ -281,30 +310,71 @@ func parseHelloArgument(arg string) (string, error) {
|
|||||||
return domain, nil
|
return domain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Session) loginHandler(line string) {
|
||||||
|
// Content and length of username is ignored.
|
||||||
|
s.send(fmt.Sprintf("334 %v", passwordChallenge))
|
||||||
|
s.enterState(PASSWORD)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) passwordHandler(line string) {
|
||||||
|
// Content and length of password is ignored.
|
||||||
|
s.send("235 Authentication successful")
|
||||||
|
s.enterState(READY)
|
||||||
|
}
|
||||||
|
|
||||||
// READY state -> waiting for MAIL
|
// READY state -> waiting for MAIL
|
||||||
|
// AUTH can change
|
||||||
func (s *Session) readyHandler(cmd string, arg string) {
|
func (s *Session) readyHandler(cmd string, arg string) {
|
||||||
if cmd == "STARTTLS" {
|
if cmd == "STARTTLS" {
|
||||||
if !s.Server.config.TLSEnabled {
|
if !s.Server.config.TLSEnabled {
|
||||||
// invalid command since unconfigured
|
// Invalid command since TLS unconfigured.
|
||||||
s.logger.Debug().Msgf("454 TLS unavailable on the server")
|
s.logger.Debug().Msgf("454 TLS unavailable on the server")
|
||||||
s.send("454 TLS unavailable on the server")
|
s.send("454 TLS unavailable on the server")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.tlsState != nil {
|
if s.tlsState != nil {
|
||||||
// tls state previously valid
|
// TLS state previously valid.
|
||||||
s.logger.Debug().Msg("454 A TLS session already agreed upon.")
|
s.logger.Debug().Msg("454 A TLS session already agreed upon.")
|
||||||
s.send("454 A TLS session already agreed upon.")
|
s.send("454 A TLS session already agreed upon.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.logger.Debug().Msg("Initiating TLS context.")
|
s.logger.Debug().Msg("Initiating TLS context.")
|
||||||
|
|
||||||
|
// Start TLS connection handshake.
|
||||||
s.send("220 STARTTLS")
|
s.send("220 STARTTLS")
|
||||||
// start tls connection handshake
|
|
||||||
tlsConn := tls.Server(s.conn, s.Server.tlsConfig)
|
tlsConn := tls.Server(s.conn, s.Server.tlsConfig)
|
||||||
s.conn = tlsConn
|
s.conn = tlsConn
|
||||||
s.text = textproto.NewConn(s.conn)
|
s.text = textproto.NewConn(s.conn)
|
||||||
s.tlsState = new(tls.ConnectionState)
|
s.tlsState = new(tls.ConnectionState)
|
||||||
*s.tlsState = tlsConn.ConnectionState()
|
*s.tlsState = tlsConn.ConnectionState()
|
||||||
s.enterState(GREET)
|
s.enterState(GREET)
|
||||||
|
} else if cmd == "AUTH" {
|
||||||
|
args := strings.SplitN(arg, " ", 3)
|
||||||
|
authMethod := args[0]
|
||||||
|
switch authMethod {
|
||||||
|
case "PLAIN":
|
||||||
|
{
|
||||||
|
if len(args) != 2 {
|
||||||
|
s.send("500 Bad auth arguments")
|
||||||
|
s.logger.Warn().Msgf("Bad auth attempt: %q", arg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.logger.Info().Msgf("Accepting credentials: %q", args[1])
|
||||||
|
s.send("235 2.7.0 Authentication successful")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "LOGIN":
|
||||||
|
{
|
||||||
|
s.send(fmt.Sprintf("334 %v", usernameChallenge))
|
||||||
|
s.enterState(LOGIN)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
s.send(fmt.Sprintf("500 Unsupported AUTH method: %v", authMethod))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if cmd == "MAIL" {
|
} else if cmd == "MAIL" {
|
||||||
// Capture group 1: from address. 2: optional params.
|
// Capture group 1: from address. 2: optional params.
|
||||||
m := fromRegex.FindStringSubmatch(arg)
|
m := fromRegex.FindStringSubmatch(arg)
|
||||||
@@ -518,30 +588,28 @@ func (s *Session) readLine() (line string, err error) {
|
|||||||
|
|
||||||
func (s *Session) parseCmd(line string) (cmd string, arg string, ok bool) {
|
func (s *Session) parseCmd(line string) (cmd string, arg string, ok bool) {
|
||||||
line = strings.TrimRight(line, "\r\n")
|
line = strings.TrimRight(line, "\r\n")
|
||||||
l := len(line)
|
|
||||||
|
// Find length of command or entire line.
|
||||||
|
hasArg := true
|
||||||
|
l := strings.IndexByte(line, ' ')
|
||||||
|
if l == -1 {
|
||||||
|
hasArg = false
|
||||||
|
l = len(line)
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case l == 0:
|
case l == 0:
|
||||||
return "", "", true
|
return "", "", true
|
||||||
case l < 4:
|
case l < 4:
|
||||||
s.logger.Warn().Msgf("Command too short: %q", line)
|
s.logger.Warn().Msgf("Command too short: %q", line)
|
||||||
return "", "", false
|
return "", "", false
|
||||||
case l == 4 || l == 8:
|
|
||||||
return strings.ToUpper(line), "", true
|
|
||||||
case l == 5:
|
|
||||||
// Too long to be only command, too short to have args
|
|
||||||
s.logger.Warn().Msgf("Mangled command: %q", line)
|
|
||||||
return "", "", false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we made it here, command is long enough to have args
|
if hasArg {
|
||||||
if line[4] != ' ' {
|
return strings.ToUpper(line[0:l]), strings.Trim(line[l+1:], " "), true
|
||||||
// There wasn't a space after the command?
|
|
||||||
s.logger.Warn().Msgf("Mangled command: %q", line)
|
|
||||||
return "", "", false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// I'm not sure if we should trim the args or not, but we will for now
|
return strings.ToUpper(line), "", true
|
||||||
return strings.ToUpper(line[0:4]), strings.Trim(line[5:], " "), true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseArgs takes the arguments proceeding a command and files them
|
// parseArgs takes the arguments proceeding a command and files them
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ func TestGreetState(t *testing.T) {
|
|||||||
if err := playSession(t, server, []scriptStep{{"helo 127.0.0.1", 250}}); err != nil {
|
if err := playSession(t, server, []scriptStep{{"helo 127.0.0.1", 250}}); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
if err := playSession(t, server, []scriptStep{{"HELO ABC", 250}}); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Valid EHLOs
|
// Valid EHLOs
|
||||||
if err := playSession(t, server, []scriptStep{{"EHLO mydomain", 250}}); err != nil {
|
if err := playSession(t, server, []scriptStep{{"EHLO mydomain", 250}}); err != nil {
|
||||||
@@ -70,6 +73,9 @@ func TestGreetState(t *testing.T) {
|
|||||||
if err := playSession(t, server, []scriptStep{{"ehlo 127.0.0.1", 250}}); err != nil {
|
if err := playSession(t, server, []scriptStep{{"ehlo 127.0.0.1", 250}}); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
if err := playSession(t, server, []scriptStep{{"EHLO a", 250}}); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
// Wait for handler to finish logging
|
// Wait for handler to finish logging
|
||||||
@@ -108,6 +114,50 @@ func TestEmptyEnvelope(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test AUTH
|
||||||
|
func TestAuth(t *testing.T) {
|
||||||
|
ds := test.NewStore()
|
||||||
|
server, logbuf, teardown := setupSMTPServer(ds)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
// PLAIN AUTH
|
||||||
|
script := []scriptStep{
|
||||||
|
{"EHLO localhost", 250},
|
||||||
|
{"AUTH PLAIN aW5idWNrZXQ6cGFzc3dvcmQK", 235},
|
||||||
|
{"RSET", 250},
|
||||||
|
{"AUTH GSSAPI aW5idWNrZXQ6cGFzc3dvcmQK", 500},
|
||||||
|
{"RSET", 250},
|
||||||
|
{"AUTH PLAIN", 500},
|
||||||
|
{"RSET", 250},
|
||||||
|
{"AUTH PLAIN aW5idWNrZXQ6cG Fzc3dvcmQK", 500},
|
||||||
|
}
|
||||||
|
if err := playSession(t, server, script); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOGIN AUTH
|
||||||
|
script = []scriptStep{
|
||||||
|
{"EHLO localhost", 250},
|
||||||
|
{"AUTH LOGIN", 334}, // Test with user/pass present.
|
||||||
|
{"username", 334},
|
||||||
|
{"password", 235},
|
||||||
|
{"RSET", 250},
|
||||||
|
{"AUTH LOGIN", 334}, // Test with empty user/pass.
|
||||||
|
{"", 334},
|
||||||
|
{"", 235},
|
||||||
|
}
|
||||||
|
if err := playSession(t, server, script); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Failed() {
|
||||||
|
// Wait for handler to finish logging
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
// Dump buffered log data if there was a failure
|
||||||
|
_, _ = io.Copy(os.Stderr, logbuf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test commands in READY state
|
// Test commands in READY state
|
||||||
func TestReadyState(t *testing.T) {
|
func TestReadyState(t *testing.T) {
|
||||||
ds := test.NewStore()
|
ds := test.NewStore()
|
||||||
@@ -159,6 +209,15 @@ func TestReadyState(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test Start TLS parsing.
|
||||||
|
script = []scriptStep{
|
||||||
|
{"HELO localhost", 250},
|
||||||
|
{"STARTTLS", 454}, // TLS unconfigured.
|
||||||
|
}
|
||||||
|
if err := playSession(t, server, script); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
// Wait for handler to finish logging
|
// Wait for handler to finish logging
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ func spaTemplateHandler(tmpl *template.Template, basePath string,
|
|||||||
BasePath: basePath,
|
BasePath: basePath,
|
||||||
}
|
}
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// ensure we do now allow click jacking
|
||||||
|
w.Header().Set("X-Frame-Options", "SameOrigin")
|
||||||
err := tmpl.Execute(w, tmplData)
|
err := tmpl.Execute(w, tmplData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Str("module", "web").Str("remote", req.RemoteAddr).Str("proto", req.Proto).
|
log.Error().Str("module", "web").Str("remote", req.RemoteAddr).Str("proto", req.Proto).
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func TestMaxSize(t *testing.T) {
|
|||||||
go func(mailbox string) {
|
go func(mailbox string) {
|
||||||
err := s.PurgeMessages(mailbox)
|
err := s.PurgeMessages(mailbox)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
panic(err) // Cannot call t.Fatal from non-test goroutine.
|
||||||
}
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(mailbox)
|
}(mailbox)
|
||||||
|
|||||||
@@ -3,15 +3,18 @@ stdenv.mkDerivation rec {
|
|||||||
name = "env";
|
name = "env";
|
||||||
env = buildEnv { name = name; paths = buildInputs; };
|
env = buildEnv { name = name; paths = buildInputs; };
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
|
act
|
||||||
dpkg
|
dpkg
|
||||||
elmPackages.elm
|
elmPackages.elm
|
||||||
elmPackages.elm-analyse
|
elmPackages.elm-analyse
|
||||||
elmPackages.elm-format
|
elmPackages.elm-format
|
||||||
|
elmPackages.elm-json
|
||||||
elmPackages.elm-language-server
|
elmPackages.elm-language-server
|
||||||
elmPackages.elm-test
|
elmPackages.elm-test
|
||||||
go
|
go
|
||||||
golint
|
golint
|
||||||
nodejs-10_x
|
nodejs-16_x
|
||||||
|
nodePackages.yarn
|
||||||
rpm
|
rpm
|
||||||
swaks
|
swaks
|
||||||
];
|
];
|
||||||
|
|||||||
4
ui/.parcelrc
Normal file
4
ui/.parcelrc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"extends": "@parcel/config-default",
|
||||||
|
"namers": [ "parcel-namer-rewrite" ]
|
||||||
|
}
|
||||||
12
ui/.proxyrc.json
Normal file
12
ui/.proxyrc.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"/api": {
|
||||||
|
"target": "http://localhost:9000",
|
||||||
|
"ws": true
|
||||||
|
},
|
||||||
|
"/debug": {
|
||||||
|
"target": "http://localhost:9000"
|
||||||
|
},
|
||||||
|
"/serve": {
|
||||||
|
"target": "http://localhost:9000"
|
||||||
|
}
|
||||||
|
}
|
||||||
14
ui/README.md
14
ui/README.md
@@ -11,9 +11,8 @@ One time setup (assuming [Node.js] is already installed):
|
|||||||
|
|
||||||
```
|
```
|
||||||
cd $INBUCKET/ui
|
cd $INBUCKET/ui
|
||||||
npm i elm -g
|
yarn install
|
||||||
npm i
|
yarn build
|
||||||
npm run build
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This will the create `node_modules`, `elm-stuff`, and `dist` directories.
|
This will the create `node_modules`, `elm-stuff`, and `dist` directories.
|
||||||
@@ -30,15 +29,16 @@ Inbucket will start, with HTTP listening on port 9000. You may verify the web
|
|||||||
UI is functional if this is your first time building Inbucket, but your dev/test
|
UI is functional if this is your first time building Inbucket, but your dev/test
|
||||||
cycle should favor the development server below.
|
cycle should favor the development server below.
|
||||||
|
|
||||||
### Terminal 2: webpack development server
|
### Terminal 2: parcel development server
|
||||||
|
|
||||||
```
|
```
|
||||||
cd $INBUCKET/ui
|
cd $INBUCKET/ui
|
||||||
npm run dev
|
yarn start
|
||||||
```
|
```
|
||||||
|
|
||||||
npm will start a development HTTP server listening on port 3000. You should use
|
yarn will start a development HTTP server listening on port 1234. You should
|
||||||
this server for UI development, as it features hot reload and the Elm debugger.
|
use this server for UI development, as it features hot reload and the Elm
|
||||||
|
debugger.
|
||||||
|
|
||||||
[Elm]: https://elm-lang.org
|
[Elm]: https://elm-lang.org
|
||||||
[Node.js]: https://nodejs.org
|
[Node.js]: https://nodejs.org
|
||||||
|
|||||||
8006
ui/package-lock.json
generated
8006
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,30 +4,29 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rm -rf dist elm-stuff",
|
"build": "parcel build --public-url ./",
|
||||||
"build": "webpack --mode production",
|
"start": "parcel --hmr-port 1235 src/index-dev.html",
|
||||||
"watch": "webpack --mode development --watch",
|
"clean": "rm -rf .parcel-cache dist elm-stuff"
|
||||||
"dev": "webpack-dev-server --mode development --port 3000 --hot --watch",
|
|
||||||
"errors": "webpack --mode development --display-error-details"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"source": "src/index.html",
|
||||||
"opensans-npm-webfont": "^1.0.0"
|
"parcel-namer-rewrite": {
|
||||||
|
"rules": {
|
||||||
|
"(.*)\\.(css|js|json|eot|png|svg|ttf|webmanifest|woff|woff2)": "static/$1{.hash}.$2"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
"browserslist": "defaults",
|
||||||
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.11.6",
|
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||||
"@babel/preset-env": "^7.11.5",
|
"@parcel/packager-raw-url": "2.4.1",
|
||||||
"@fortawesome/fontawesome-free": "^5.14.0",
|
"@parcel/transformer-elm": "^2.2.1",
|
||||||
"@webcomponents/webcomponentsjs": "^2.4.4",
|
"@parcel/transformer-webmanifest": "2.4.1",
|
||||||
"babel-loader": "^8.1.0",
|
"@webcomponents/webcomponentsjs": "^2.5.0",
|
||||||
"css-loader": "^4.3.0",
|
"opensans-npm-webfont": "^1.0.0",
|
||||||
"elm-hot-webpack-loader": "^1.1.7",
|
"parcel": "^2.4.1",
|
||||||
"elm-webpack-loader": "^7.0.1",
|
"parcel-namer-rewrite": "^2.0.0-rc.2"
|
||||||
"file-loader": "^6.1.0",
|
},
|
||||||
"html-webpack-plugin": "^4.5.0",
|
"optionalDependencies": {
|
||||||
"node-elm-compiler": "^5.0.5",
|
"elm": "^0.19.1-5"
|
||||||
"style-loader": "^1.2.1",
|
|
||||||
"webpack": "^4.44.2",
|
|
||||||
"webpack-cli": "^3.3.12",
|
|
||||||
"webpack-dev-server": "^3.11.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
@@ -1,15 +1,20 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<!-- This index file will be served by the webpack development server. -->
|
<!-- This index file will be served by the development server. -->
|
||||||
<base href="/">
|
<base href="/">
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<meta name="theme-color" content="#000000">
|
<meta name="theme-color" content="#000000">
|
||||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||||
<meta http-equiv="Pragma" content="no-cache" />
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
<meta http-equiv="Expires" content="0" />
|
<meta http-equiv="Expires" content="0">
|
||||||
|
<link rel="stylesheet" href="./main.css">
|
||||||
|
<link rel="stylesheet" href="./navbar.css">
|
||||||
|
<link rel="stylesheet" href="./mailbox.css">
|
||||||
|
<link rel="icon" type="image/png" href="./favicon.png">
|
||||||
|
<link rel="manifest" href="./manifest.json">
|
||||||
<title>Inbucket</title>
|
<title>Inbucket</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -17,5 +22,6 @@
|
|||||||
You need to enable JavaScript to run this app.
|
You need to enable JavaScript to run this app.
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
<script type="module" src="index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -6,9 +6,14 @@
|
|||||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<meta name="theme-color" content="#000000">
|
<meta name="theme-color" content="#000000">
|
||||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||||
<meta http-equiv="Pragma" content="no-cache" />
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
<meta http-equiv="Expires" content="0" />
|
<meta http-equiv="Expires" content="0">
|
||||||
|
<link rel="stylesheet" href="./main.css">
|
||||||
|
<link rel="stylesheet" href="./navbar.css">
|
||||||
|
<link rel="stylesheet" href="./mailbox.css">
|
||||||
|
<link rel="icon" type="image/png" href="./favicon.png">
|
||||||
|
<link rel="manifest" href="./manifest.json">
|
||||||
<title>Inbucket</title>
|
<title>Inbucket</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -16,5 +21,6 @@
|
|||||||
You need to enable JavaScript to run this app.
|
You need to enable JavaScript to run this app.
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
<script type="module" src="index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
import './main.css'
|
|
||||||
import './mailbox.css'
|
|
||||||
import './navbar.css'
|
|
||||||
import '@fortawesome/fontawesome-free/css/all.css'
|
import '@fortawesome/fontawesome-free/css/all.css'
|
||||||
import '@webcomponents/webcomponentsjs/webcomponents-bundle'
|
import '@webcomponents/webcomponentsjs/webcomponents-bundle'
|
||||||
import 'opensans-npm-webfont'
|
import 'opensans-npm-webfont'
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
.message-list {
|
.message-list {
|
||||||
display: block;
|
display: block;
|
||||||
overflow-y: scroll;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-list-controls {
|
.message-list-controls {
|
||||||
|
|||||||
119
ui/src/main.css
119
ui/src/main.css
@@ -11,6 +11,68 @@
|
|||||||
--selected-color: #eee;
|
--selected-color: #eee;
|
||||||
--focused-color: #fff;
|
--focused-color: #fff;
|
||||||
--focused-bg-color: #337ab7;
|
--focused-bg-color: #337ab7;
|
||||||
|
|
||||||
|
--input-bg: white;
|
||||||
|
--input-bg-active: white;
|
||||||
|
|
||||||
|
--btn-default-bg-color: #337ab7;
|
||||||
|
--btn-default-bg-image: linear-gradient(to bottom, #337ab7 0, #265a88 100%);
|
||||||
|
--btn-default-color: #ffffff;
|
||||||
|
--btn-danger-bg-color: #d9534f;
|
||||||
|
--btn-danger-bg-image: linear-gradient(to bottom, #d9534f 0, #c12e2a 100%);
|
||||||
|
--btn-light-bg-color: #eee;
|
||||||
|
--btn-light-bg-image: linear-gradient(to bottom, #f0f0f0 0, #e0e0e0 100%);
|
||||||
|
|
||||||
|
--monitor-header-bg: #e8e8e8;
|
||||||
|
|
||||||
|
--well-bg-color: #f5f5f5;
|
||||||
|
--well-bg-image: linear-gradient(to bottom, #e8e8e8 0, #f5f5f5 100%);
|
||||||
|
|
||||||
|
--well-warn-bg-color: #fff8cf;
|
||||||
|
--well-warn-bg-image: linear-gradient(to bottom, #fff899 0, #fff8cf 100%);
|
||||||
|
--well-warn-color: inherit;
|
||||||
|
|
||||||
|
--well-error-bg-color: #f58080;
|
||||||
|
--well-error-bg-image: linear-gradient(to bottom, #e86060 0, #f58080 100%);
|
||||||
|
--well-error-color: inherit;
|
||||||
|
|
||||||
|
--well-border: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--bg-color: #202124;
|
||||||
|
--primary-color: #bdc1c6;
|
||||||
|
--high-color: #8ab4f8;
|
||||||
|
--border-color: #5f6368;
|
||||||
|
--selected-color: #303134;
|
||||||
|
|
||||||
|
--input-bg: var(--bg-color);
|
||||||
|
--input-bg-active: rgb(48, 49, 52);
|
||||||
|
|
||||||
|
--btn-default-bg-color: #303134;
|
||||||
|
--btn-default-bg-image: none;
|
||||||
|
--btn-default-color: #e8eaed;
|
||||||
|
/*--btn-danger-bg-color: #d9534f;*/
|
||||||
|
--btn-danger-bg-image: none;
|
||||||
|
/*--btn-light-bg-color: #eee;*/
|
||||||
|
--btn-light-bg-image: none;
|
||||||
|
|
||||||
|
--monitor-header-bg: var(--selected-color);
|
||||||
|
|
||||||
|
--well-bg-color: var(--low-color);
|
||||||
|
--well-bg-image: none;
|
||||||
|
|
||||||
|
--well-warn-bg-color: #c3c099;
|
||||||
|
--well-warn-bg-image: none;
|
||||||
|
--well-warn-color: var(--bg-color);
|
||||||
|
|
||||||
|
--well-error-bg-color: #e86060;
|
||||||
|
--well-error-bg-image: none;
|
||||||
|
--well-error-color: var(--bg-color);
|
||||||
|
|
||||||
|
--well-border: var(--border-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body, div, span, applet, object, iframe,
|
html, body, div, span, applet, object, iframe,
|
||||||
@@ -39,7 +101,7 @@ time, mark, audio, video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #337ab7;
|
color: var(--high-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,8 +129,8 @@ h1, h2, h3, h4, h5, h6, p {
|
|||||||
/** SHARED */
|
/** SHARED */
|
||||||
|
|
||||||
a.button {
|
a.button {
|
||||||
background-color: #337ab7;
|
background-color: var(--btn-default-bg-color);
|
||||||
background-image: linear-gradient(to bottom, #337ab7 0, #265a88 100%);
|
background-image: var(--btn-default-bg-image);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -82,11 +144,9 @@ a.button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.well {
|
.well {
|
||||||
--light: #f5f5f5;
|
background-color: var(--well-bg-color);
|
||||||
--dark: #e8e8e8;
|
background-image: var(--well-bg-image);
|
||||||
background-color: var(--light);
|
border: 1px solid var(--well-border);
|
||||||
background-image: linear-gradient(to bottom, var(--dark) 0, var(--light) 100%);
|
|
||||||
border: 1px solid var(--dark);
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-shadow: 0 1px 2px rgba(0,0,0,.05);
|
box-shadow: 0 1px 2px rgba(0,0,0,.05);
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
@@ -98,8 +158,9 @@ a.button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.well-error {
|
.well-error {
|
||||||
--light: #f58080;
|
background-color: var(--well-error-bg-color);
|
||||||
--dark: #e86060;
|
background-image: var(--well-error-bg-image);
|
||||||
|
color: var(--well-error-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.well-error a {
|
.well-error a {
|
||||||
@@ -108,8 +169,22 @@ a.button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.well-warn {
|
.well-warn {
|
||||||
--light: #fff8cf;
|
background-color: var(--well-warn-bg-color);
|
||||||
--dark: #fff899;
|
background-image: var(--well-warn-bg-image);
|
||||||
|
color: var(--well-warn-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background-color: var(--input-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
input:focus-visible, input:hover {
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid var(--input-bg-active);
|
||||||
|
background-color: var(--input-bg-active);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** APP */
|
/** APP */
|
||||||
@@ -237,11 +312,11 @@ h3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.button-bar button {
|
.button-bar button {
|
||||||
background-color: #337ab7;
|
background-color: var(--btn-default-bg-color);
|
||||||
background-image: linear-gradient(to bottom, #337ab7 0, #265a88 100%);
|
background-image: var(--btn-default-bg-image);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: #fff;
|
color: var(--btn-default-color);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@@ -254,18 +329,22 @@ h3 {
|
|||||||
text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
|
text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-bar button:hover {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
.button-bar *:not(:last-child) {
|
.button-bar *:not(:last-child) {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-bar button.danger {
|
.button-bar button.danger {
|
||||||
background-color: #d9534f;
|
background-color: var(--btn-danger-bg-color);
|
||||||
background-image: linear-gradient(to bottom, #d9534f 0, #c12e2a 100%);
|
background-image: var(--btn-danger-bg-image);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-bar button.light {
|
.button-bar button.light {
|
||||||
background-color: #eee;
|
background-color: var(--btn-light-bg-color);
|
||||||
background-image: linear-gradient(to bottom, #f0f0f0 0, #e0e0e0 100%);
|
background-image: var(--btn-light-bg-image);
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +364,7 @@ h3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.metric-panel h2 {
|
.metric-panel h2 {
|
||||||
background-image: linear-gradient(to bottom, #f5f5f5 0, #e8e8e8 100%);
|
background-color: var(--monitor-header-bg);
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|||||||
@@ -2,16 +2,34 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--navbar-color: #9d9d9d;
|
--navbar-color: #9d9d9d;
|
||||||
|
--navbar-color-active: var(--navbar-color);
|
||||||
--navbar-bg: #222;
|
--navbar-bg: #222;
|
||||||
|
--navbar-bg-active: #080808;
|
||||||
|
--navbar-bg-border-active: none;
|
||||||
--navbar-image: linear-gradient(to bottom, #3c3c3c 0, #222 100%);
|
--navbar-image: linear-gradient(to bottom, #3c3c3c 0, #222 100%);
|
||||||
--navbar-height: 50px;
|
--navbar-height: 50px;
|
||||||
|
--navbar-border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--navbar-color: #969ba1;
|
||||||
|
--navbar-color-active: #8ab4f8;
|
||||||
|
--navbar-bg: var(--bg-color);
|
||||||
|
--navbar-bg-active: none;
|
||||||
|
--navbar-bg-border-active: 3px solid var(--navbar-color-active);
|
||||||
|
--navbar-image: none;
|
||||||
|
--navbar-border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
background-color: var(--navbar-bg);
|
background-color: var(--navbar-bg);
|
||||||
background-image: var(--navbar-image);
|
background-image: var(--navbar-image);
|
||||||
text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
|
text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
|
||||||
min-height: var(--navbar-height);
|
min-height: var(--navbar-height);
|
||||||
|
border-bottom: var(--navbar-border-bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-nav {
|
.main-nav {
|
||||||
@@ -66,7 +84,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
li.navbar-active > *:first-child {
|
li.navbar-active > *:first-child {
|
||||||
background-color: #080808;
|
background-color: var(--navbar-bg-active);
|
||||||
|
color: var(--navbar-color-active);
|
||||||
|
border-bottom: var(--navbar-bg-border-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
li.navbar-active a,
|
li.navbar-active a,
|
||||||
@@ -92,7 +112,6 @@ li.navbar-active span,
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navbar-mailbox input {
|
.navbar-mailbox input {
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
|
|
||||||
module.exports = (env, argv) => {
|
|
||||||
const production = argv.mode === 'production'
|
|
||||||
const config = {
|
|
||||||
output: {
|
|
||||||
filename: 'static/[name].[hash:8].js',
|
|
||||||
publicPath: '',
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
exclude: [/elm-stuff/, /node_modules/],
|
|
||||||
loader: 'babel-loader',
|
|
||||||
query: {
|
|
||||||
presets: [
|
|
||||||
'@babel/preset-env',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.elm$/,
|
|
||||||
exclude: [/elm-stuff/, /node_modules/],
|
|
||||||
use: [
|
|
||||||
{ loader: 'elm-hot-webpack-loader' },
|
|
||||||
{
|
|
||||||
loader: 'elm-webpack-loader',
|
|
||||||
options: {
|
|
||||||
debug: !production,
|
|
||||||
optimize: production,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
loader: ['style-loader', 'css-loader'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(eot|svg|ttf|woff|woff2)$/,
|
|
||||||
loader: 'file-loader',
|
|
||||||
options: {
|
|
||||||
name: 'static/[name].[hash:8].[ext]',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: 'public/index.html',
|
|
||||||
favicon: 'public/favicon.png',
|
|
||||||
}),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
filename: 'index-dev.html',
|
|
||||||
template: 'public/index-dev.html',
|
|
||||||
favicon: 'public/favicon.png',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
devServer: {
|
|
||||||
historyApiFallback: {
|
|
||||||
index: '/index-dev.html',
|
|
||||||
},
|
|
||||||
index: 'index-dev.html',
|
|
||||||
inline: true,
|
|
||||||
overlay: true,
|
|
||||||
open: true,
|
|
||||||
proxy: [{
|
|
||||||
context: ['/api', '/debug', '/serve'],
|
|
||||||
target: 'http://localhost:9000',
|
|
||||||
ws: true,
|
|
||||||
}],
|
|
||||||
stats: { colors: true },
|
|
||||||
watchOptions: {
|
|
||||||
ignored: /node_modules/,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if (argv.hot) {
|
|
||||||
config.plugins.push(new webpack.HotModuleReplacementPlugin())
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
2231
ui/yarn.lock
Normal file
2231
ui/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user