1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 09:37:02 +00:00

Compare commits

...

21 Commits

Author SHA1 Message Date
James Hillyerd
997c6307b8 chore: Update Go version to 1.25 in release workflow 2025-11-22 11:46:30 -08:00
dependabot[bot]
e0824eb0aa build(deps): bump actions/setup-node from 4 to 6 (#582)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-22 11:44:05 -08:00
dependabot[bot]
f210b4c47c build(deps): bump actions/setup-go from 5 to 6 (#580)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-22 11:38:57 -08:00
James Hillyerd
2ea0639509 chore: Update Go version in lint workflow to 1.25 (#586) 2025-11-22 11:35:33 -08:00
dependabot[bot]
4399d02f0b build(deps): bump actions/checkout from 4 to 5 (#578)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-22 10:42:57 -08:00
dependabot[bot]
25007f4506 build(deps): bump js-yaml from 4.1.0 to 4.1.1 in /ui (#584)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.0 to 4.1.1.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-22 10:42:34 -08:00
James Hillyerd
fe0e3a00e1 chore: bump go to 1.25 (#585)
Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-11-22 10:41:48 -08:00
James Hillyerd
577a329240 Changelog for v3.1.0 (#577)
Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-07-27 12:14:00 -07:00
James Hillyerd
c3a8eb8e3b fix: Note missing script is not an error (#575)
Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-07-27 11:33:04 -07:00
James Hillyerd
273c6a5dbd fix: context related lints (#576)
* fix: POP3 server now uses TLS HandshakeContext

Signed-off-by: James Hillyerd <james@hillyerd.com>

* fix: Web server now uses Listen with context

Signed-off-by: James Hillyerd <james@hillyerd.com>

* fix: replace interface{} with any

Signed-off-by: James Hillyerd <james@hillyerd.com>

---------

Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-07-27 11:25:03 -07:00
James Hillyerd
f799e3debf chore: modernize range loops (#574)
Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-05-31 12:57:47 -07:00
James Hillyerd
8a1a01660c chore: update goreleaser deprecated formats (#573)
Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-05-10 12:56:16 -07:00
dependabot[bot]
d1f2ae7946 build(deps): bump base-x from 3.0.9 to 3.0.11 in /ui (#564)
Bumps [base-x](https://github.com/cryptocoinjs/base-x) from 3.0.9 to 3.0.11.
- [Commits](https://github.com/cryptocoinjs/base-x/compare/v3.0.9...v3.0.11)

---
updated-dependencies:
- dependency-name: base-x
  dependency-version: 3.0.11
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-09 08:16:15 -07:00
dependabot[bot]
8339cb5378 build(deps): bump golangci/golangci-lint-action from 7 to 8 (#565)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 6 to 8.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v6...v8)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-09 07:39:25 -07:00
James Hillyerd
cf92969719 chore: Update golangci lint to 2.0.x (#572)
* Update to golangci lint 2.0.x

Signed-off-by: James Hillyerd <james@hillyerd.com>

* Fix new lint warnings

Signed-off-by: James Hillyerd <james@hillyerd.com>

---------

Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-05-08 21:23:42 -07:00
James Hillyerd
9a2b0f934a chore: Update Go deps (#571)
* chore: Update Go deps

Signed-off-by: James Hillyerd <james@hillyerd.com>

* Fix lint warnings for loopvars

Signed-off-by: James Hillyerd <james@hillyerd.com>

---------

Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-05-08 20:53:25 -07:00
James Hillyerd
b99cf9b6dc chore: Build with Go 1.24 (#568)
Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-05-08 20:41:54 -07:00
James Hillyerd
f6d00dfcb2 Update expired linters (#569)
Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-05-08 20:37:42 -07:00
Steve Atkins
440fddfe46 Add the 821.From / return-path of an email to the stored message (#560)
as a Return-Path: header. This is visible in the source view and as a
header via the REST API.

Signed-off-by: Steve Atkins <steve@wordtothewise.com>
2025-03-18 08:28:31 -07:00
Steve Atkins
9904399d24 Accept and handle emails sent with an empty 821.From / return-path as… (#561)
* Accept and handle emails sent with an empty 821.From / return-path as it would any other email.
2025-03-17 08:54:30 -07:00
Sander
4c8c8e7744 Update README.md (#556)
I copied the command from the website at [/packages/docker.html](https://inbucket.org/packages/docker.html). I thought it would be convenient if people could directly copy the command to run the image locally from the readme.
2025-02-17 09:13:57 -08:00
34 changed files with 202 additions and 145 deletions

View File

@@ -13,13 +13,13 @@ jobs:
strategy:
matrix:
go:
- '1.23'
- '1.25'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go }}
check-latest: true
@@ -38,13 +38,13 @@ jobs:
runs-on: windows-latest
name: Windows Go build
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '1.23'
go-version: '1.25'
- name: Build
run: go build ./...
- name: Test
@@ -60,11 +60,11 @@ jobs:
runs-on: ubuntu-latest
name: UI Build
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20.x'
cache: 'yarn'

View File

@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Docker meta
id: meta

View File

@@ -7,11 +7,11 @@ jobs:
golangci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with:
go-version: '1.23'
go-version: '1.25'
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v8
with:
version: latest

View File

@@ -13,18 +13,18 @@ jobs:
name: 'Go Releaser'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '1.23'
go-version: '1.25'
check-latest: true
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20.x'
cache: 'yarn'

View File

@@ -1,5 +1,4 @@
run:
timeout: 5m
version: "2"
linters:
enable:
- asasalint
@@ -8,31 +7,19 @@ linters:
- bodyclose
- containedctx
- contextcheck
- copyloopvar
- decorder
# - dupl
# - dupword
- durationcheck
- errchkjson
- errname
# - errorlint
# - exhaustive
- exportloopref
# - forcetypeassert
- ginkgolinter
- gocheckcompilerdirectives
# - gochecknoinits
- gochecksumtype
- gocritic
# - godot
# - goerr113
- gofmt
# - gofumpt
- goheader
- goimports
- gomoddirectives
- gomodguard
- goprintffuncname
# - gosec
- gosmopolitan
- grouper
- importas
@@ -44,8 +31,6 @@ linters:
- misspell
- musttag
- nilerr
# - nilnil
# - nlreturn
- noctx
- nolintlint
- nosprintfhostport
@@ -55,24 +40,43 @@ linters:
- promlinter
- protogetter
- reassign
# - revive
- rowserrcheck
- sloglint
- stylecheck
- staticcheck
- tagliatelle
- tenv
- testableexamples
- testifylint
- thelper
- tparallel
# - unconvert
- unparam
- usestdlibvars
- usetesting
- wastedassign
- whitespace
- zerologlint
linters-settings:
tagliatelle:
case:
rules:
json: kebab
settings:
tagliatelle:
case:
rules:
json: kebab
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View File

@@ -49,11 +49,11 @@ builds:
archives:
- id: tarball
format: tar.gz
formats: tar.gz
wrap_in_directory: true
format_overrides:
- goos: windows
format: zip
formats: zip
files:
- LICENSE*
- README*

View File

@@ -7,6 +7,15 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
## [v3.1.0] - 2025-07-27
### Added
- Note in logs that a missing Lua script is not an error (#575)
### Fixed
- Accept and handle emails sent with an empty 821.From (#561)
## [v3.1.0-beta3] - 2024-11-02
### Added
@@ -370,7 +379,8 @@ No change from beta1.
specific message.
[Unreleased]: https://github.com/inbucket/inbucket/compare/v3.1.0-beta3...main
[Unreleased]: https://github.com/inbucket/inbucket/compare/v3.1.0...main
[v3.1.0]: https://github.com/inbucket/inbucket/compare/v3.1.0-beta3...v3.1.0
[v3.1.0-beta3]: https://github.com/inbucket/inbucket/compare/v3.1.0-beta2...v3.1.0-beta3
[v3.1.0-beta2]: https://github.com/inbucket/inbucket/compare/v3.1.0-beta1...v3.1.0-beta2
[v3.1.0-beta1]: https://github.com/inbucket/inbucket/compare/v3.0.4...v3.1.0-beta1
@@ -409,7 +419,7 @@ No change from beta1.
- Add new GitHub `/compare` link
- Update previous tag version for *Unreleased*
3. Run tests
4. Update goreleaser, and then test cross-compile: `goreleaser --snapshot`
4. Update goreleaser, and then test cross-compile: `goreleaser release --snapshot --clean`
5. Commit changes and merge release PR into main
6. Create new release via GitHub, use CHANGELOG release notes, tag `vX.Y.Z`
7. Push tags and wait for

View File

@@ -2,7 +2,7 @@
### Build frontend
# Due to no official elm compiler for arm; build frontend with amd64.
FROM --platform=linux/amd64 node:20 as frontend
FROM --platform=linux/amd64 node:20 AS frontend
RUN npm install -g node-gyp
WORKDIR /build
COPY . .
@@ -12,7 +12,7 @@ RUN yarn install --frozen-lockfile --non-interactive
RUN yarn run build
### Build backend
FROM golang:1.23-alpine3.20 as backend
FROM golang:1.25-alpine3.22 AS backend
RUN apk add --no-cache --virtual .build-deps g++ git make
WORKDIR /build
COPY . .
@@ -23,7 +23,7 @@ RUN go build -o inbucket \
-v ./cmd/inbucket
### Run in minimal image
FROM alpine:3.20
FROM alpine:3.22
RUN apk --no-cache add tzdata
WORKDIR /opt/inbucket
RUN mkdir bin defaults ui

View File

@@ -30,6 +30,13 @@ Inbucket has automated [Docker Image] builds via Docker Hub. The `latest` tag
tracks our tagged releases, and `edge` tracks our potentially unstable
`main` branch.
Start the docker image by running:
```
docker run -d --name inbucket -p 9000:9000 -p 2500:2500 -p 1100:1100 inbucket/inbucket
```
Then point your browser to [localhost:9000](http://localhost:9000/)
## Building from Source

View File

@@ -37,7 +37,7 @@ func init() {
startTime.Set(time.Now().UnixNano() / 1000000)
// Goroutine count for status page.
expvar.Publish("goroutines", expvar.Func(func() interface{} {
expvar.Publish("goroutines", expvar.Func(func() any {
return runtime.NumGoroutine()
}))

18
go.mod
View File

@@ -1,8 +1,6 @@
module github.com/inbucket/inbucket/v3
go 1.21
toolchain go1.21.4
go 1.25.0
require (
github.com/cjoudrey/gluahttp v0.0.0-20201111170219-25003d9adfa9
@@ -12,14 +10,14 @@ require (
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.3
github.com/inbucket/gopher-json v0.2.0
github.com/jhillyerd/enmime/v2 v2.0.0
github.com/jhillyerd/enmime/v2 v2.1.0
github.com/jhillyerd/goldiff v0.1.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/microcosm-cc/bluemonday v1.0.27
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.9.0
github.com/rs/zerolog v1.34.0
github.com/stretchr/testify v1.10.0
github.com/yuin/gopher-lua v1.1.1
golang.org/x/net v0.29.0
golang.org/x/net v0.40.0
)
require (
@@ -29,7 +27,7 @@ require (
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -39,8 +37,8 @@ require (
github.com/rivo/uniseg v0.4.7 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

29
go.sum
View File

@@ -27,8 +27,8 @@ github.com/inbucket/gopher-json v0.2.0 h1:v/luoFy5olitFhByVUGMZ3LmtcroRs9YHlyrBe
github.com/inbucket/gopher-json v0.2.0/go.mod h1:1BK2XgU9y+ibiRkylJQeV44AV9DrO8dVsgOJ6vpqF3g=
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA=
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
github.com/jhillyerd/enmime/v2 v2.0.0 h1:I39PYf0peLGroKq+uX2yGB1ExH/78HcRJy4VmERQAVk=
github.com/jhillyerd/enmime/v2 v2.0.0/go.mod h1:wQkz7BochDzSukAz5ajAQaXOB7pEg5Vh5QWs7m1uAPw=
github.com/jhillyerd/enmime/v2 v2.1.0 h1:c8Qwi5Xq5EdtMN6byQWoZ/8I2RMTo6OJ7Xay+s1oPO0=
github.com/jhillyerd/enmime/v2 v2.1.0/go.mod h1:EJ74dcRbBcqHSP2TBu08XRoy6y3Yx0cevwb1YkGMEmQ=
github.com/jhillyerd/goldiff v0.1.0 h1:7JzKPKVwAg1GzrbnsToYzq3Y5+S7dXM4hgEYiOzaf4A=
github.com/jhillyerd/goldiff v0.1.0/go.mod h1:WeDal6DTqhbMhNkf5REzWCIvKl3JWs0Q9omZ/huIWAs=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
@@ -40,8 +40,9 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -65,26 +66,26 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
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/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 h1:noHsffKZsNfU38DwcXWEPldrTjIZ8FPNKx8mYMGnqjs=
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7/go.mod h1:bbMEM6aU1WDF1ErA5YJ0p91652pGv140gGw4Ww3RGp8=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@@ -38,7 +38,7 @@ func New(conf config.Lua, extHost *extension.Host) (*Host, error) {
// Pre-load, parse, and compile script.
if fi, err := os.Stat(scriptPath); err != nil {
logger.Info().Msg("Script file not found")
logger.Info().Msg("Lua script file not found (this is not an error)")
return nil, ErrNoScript
} else if fi.IsDir() {
return nil, fmt.Errorf("lua script %v is a directory", scriptPath)

View File

@@ -112,7 +112,7 @@ func (s *StoreManager) Deliver(
for _, mb := range inbound.Mailboxes {
// Append recipient and timestamp to generated Received header.
recvd := fmt.Sprintf("%s for <%s>; %s\r\n", recvdHeader, mb, tstamp)
returnPath := fmt.Sprintf("Return-Path: <%s>\r\n", from.Address.Address)
// Deliver message.
logger.Debug().Str("mailbox", mb).Msg("Delivering message")
delivery := &Delivery{
@@ -124,7 +124,7 @@ func (s *StoreManager) Deliver(
Subject: inbound.Subject,
Size: inbound.Size,
},
Reader: io.MultiReader(strings.NewReader(recvd), bytes.NewReader(source)),
Reader: io.MultiReader(strings.NewReader(returnPath), strings.NewReader(recvd), bytes.NewReader(source)),
}
id, err := s.Store.AddMessage(delivery)
if err != nil {

View File

@@ -501,6 +501,38 @@ func TestMailboxForAddress(t *testing.T) {
assert.Equal(t, addr, got, "FullNaming mode should return a full address for mailbox")
}
func TestReturnPath(t *testing.T) {
sm, _ := testStoreManager()
recvdHeader := "Received: xyz\n"
msgSource := `From: from@example.com
To: u1@example.com
Subject: return path
test email`
// Deliver message.
origin, _ := sm.AddrPolicy.ParseOrigin("821from@example.com")
recipient, _ := sm.AddrPolicy.NewRecipient("u1@example.com")
err := sm.Deliver(origin, []*policy.Recipient{recipient}, recvdHeader, []byte(msgSource))
require.NoError(t, err)
// Find message ID.
msgs, err := sm.GetMetadata("u1@example.com")
require.NoError(t, err, "Failed to read mailbox")
require.Len(t, msgs, 1, "Unexpected mailbox len")
id := msgs[0].ID
// Read back and verify source.
r, err := sm.SourceReader("u1@example.com", id)
require.NoError(t, err, "SourceReader must succeed")
gotBytes, err := io.ReadAll(r)
require.NoError(t, err, "Failed to read source")
got := string(gotBytes)
assert.Contains(t, got, "Return-Path: <821from@example.com>\r\n", "Source should contain return-path")
}
// Returns an empty StoreManager and extension Host pair, configured for testing.
func testStoreManager() (*message.StoreManager, *extension.Host) {
extHost := extension.NewHost()

View File

@@ -81,7 +81,7 @@ func TestHubZeroLen(t *testing.T) {
hub := New(0, extension.NewHost())
go hub.Start(ctx)
m := event.MessageMetadata{}
for i := 0; i < 100; i++ {
for range 100 {
hub.Dispatch(m)
}
// Ensures Hub doesn't panic
@@ -93,7 +93,7 @@ func TestHubZeroListeners(t *testing.T) {
hub := New(5, extension.NewHost())
go hub.Start(ctx)
m := event.MessageMetadata{}
for i := 0; i < 100; i++ {
for range 100 {
hub.Dispatch(m)
}
// Ensures Hub doesn't panic
@@ -178,7 +178,7 @@ func TestHubHistoryReplay(t *testing.T) {
// Broadcast 3 messages with no listeners
msgs := make([]event.MessageMetadata, 3)
for i := 0; i < len(msgs); i++ {
for i := range msgs {
msgs[i] = event.MessageMetadata{
Subject: fmt.Sprintf("subj %v", i),
}
@@ -203,7 +203,7 @@ func TestHubHistoryReplay(t *testing.T) {
t.Fatal("Timeout:", l2)
}
for i := 0; i < len(msgs); i++ {
for i := range msgs {
got := l2.messages[i].Subject
want := msgs[i].Subject
if got != want {
@@ -222,7 +222,7 @@ func TestHubHistoryDelete(t *testing.T) {
// Broadcast 3 messages with no listeners
msgs := make([]event.MessageMetadata, 3)
for i := 0; i < len(msgs); i++ {
for i := range msgs {
msgs[i] = event.MessageMetadata{
Mailbox: "hub",
ID: strconv.Itoa(i),
@@ -253,7 +253,7 @@ func TestHubHistoryDelete(t *testing.T) {
}
want := []string{"subj 0", "subj 2"}
for i := 0; i < len(want); i++ {
for i := range want {
got := l2.messages[i].Subject
if got != want[i] {
t.Errorf("msg[%v].Subject == %q, want %q", i, got, want[i])
@@ -271,7 +271,7 @@ func TestHubHistoryReplayWrap(t *testing.T) {
// Broadcast more messages than the hub can hold
msgs := make([]event.MessageMetadata, 20)
for i := 0; i < len(msgs); i++ {
for i := range msgs {
msgs[i] = event.MessageMetadata{
Subject: fmt.Sprintf("subj %v", i),
}
@@ -296,7 +296,7 @@ func TestHubHistoryReplayWrap(t *testing.T) {
t.Fatal("Timeout:", l2)
}
for i := 0; i < 5; i++ {
for i := range 5 {
got := l2.messages[i].Subject
want := msgs[i+15].Subject
if got != want {
@@ -326,7 +326,7 @@ func TestHubHistoryReplayWrapAfterDelete(t *testing.T) {
// Broadcast more messages than the hub can hold.
msgs := make([]event.MessageMetadata, 10)
for i := 0; i < len(msgs); i++ {
for i := range msgs {
msgs[i] = event.MessageMetadata{
Mailbox: "first",
ID: strconv.Itoa(i),
@@ -343,7 +343,7 @@ func TestHubHistoryReplayWrapAfterDelete(t *testing.T) {
hub.Delete("first", "7")
// Broadcast another set of messages.
for i := 0; i < len(msgs); i++ {
for i := range msgs {
msgs[i] = event.MessageMetadata{
Mailbox: "second",
ID: strconv.Itoa(i),

View File

@@ -75,6 +75,11 @@ func (a *Addressing) NewRecipient(address string) (*Recipient, error) {
// ParseOrigin parses an address into a Origin. This is used for parsing MAIL FROM argument,
// not To headers.
func (a *Addressing) ParseOrigin(address string) (*Origin, error) {
if address == "" {
return &Origin{
addrPolicy: a,
}, nil
}
local, domain, err := ParseEmailAddress(address)
if err != nil {
return nil, err
@@ -269,7 +274,7 @@ func parseEmailAddress(address string) (local string, domain string, err error)
inCharQuote := false
inStringQuote := false
LOOP:
for i := 0; i < len(address); i++ {
for i := range len(address) {
c := address[i]
switch {
case ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'):
@@ -375,7 +380,7 @@ func parseMailboxName(localPart string) (result string, err error) {
}
result = strings.ToLower(localPart)
invalid := make([]byte, 0, 10)
for i := 0; i < len(result); i++ {
for i := range len(result) {
c := result[i]
switch {
case 'a' <= c && c <= 'z':

View File

@@ -2,6 +2,7 @@ package pop3
import (
"bufio"
"context"
"crypto/tls"
"fmt"
"io"
@@ -101,7 +102,7 @@ func (s *Session) String() string {
* 4. If bad cmd, respond error
* 5. Goto 2
*/
func (s *Server) startSession(id int, conn net.Conn) {
func (s *Server) startSession(ctx context.Context, id int, conn net.Conn) {
logger := log.With().Str("module", "pop3").Str("remote", conn.RemoteAddr().String()).
Int("session", id).Logger()
logger.Debug().Msgf("ForceTLS: %t", s.config.ForceTLS)
@@ -165,7 +166,7 @@ func (s *Server) startSession(id int, conn net.Conn) {
// Send command to handler for current state
switch ssn.state {
case AUTHORIZATION:
ssn.authorizationHandler(cmd, arg)
ssn.authorizationHandler(ctx, cmd, arg)
continue
case TRANSACTION:
ssn.transactionHandler(cmd, arg)
@@ -206,7 +207,7 @@ func (s *Server) startSession(id int, conn net.Conn) {
}
// AUTHORIZATION state
func (s *Session) authorizationHandler(cmd string, args []string) {
func (s *Session) authorizationHandler(ctx context.Context, cmd string, args []string) {
switch cmd {
case "QUIT":
s.send("+OK Goodnight and good luck")
@@ -214,7 +215,7 @@ func (s *Session) authorizationHandler(cmd string, args []string) {
s.enterState(QUIT)
case "STLS":
if !s.Server.config.TLSEnabled || s.Server.config.ForceTLS {
if !s.config.TLSEnabled || s.config.ForceTLS {
// Invalid command since TLS unconfigured.
s.logger.Debug().Msgf("-ERR TLS unavailable on the server")
s.send("-ERR TLS unavailable on the server")
@@ -229,9 +230,11 @@ func (s *Session) authorizationHandler(cmd string, args []string) {
s.logger.Debug().Msg("Initiating TLS context.")
// Start TLS connection handshake.
tlsCtx, cancel := context.WithTimeout(ctx, s.config.Timeout)
defer cancel()
s.send("+OK Begin TLS Negotiation")
tlsConn := tls.Server(s.conn, s.Server.tlsConfig)
if err := tlsConn.Handshake(); err != nil {
tlsConn := tls.Server(s.conn, s.tlsConfig)
if err := tlsConn.HandshakeContext(tlsCtx); err != nil {
s.logger.Error().Msgf("-ERR TLS handshake failed %v", err)
s.ooSeq(cmd)
}

View File

@@ -302,7 +302,7 @@ func setupPOPServer(t *testing.T, ds storage.Store, tls bool, forceTLS bool) *Se
cfg := config.POP3{
Addr: "127.0.0.1:2500",
Domain: "inbucket.local",
Timeout: 5,
Timeout: 5 * time.Second,
Debug: true,
ForceTLS: forceTLS,
}
@@ -344,7 +344,7 @@ func setupPOPSession(t *testing.T, server *Server) net.Conn {
// Start the session.
server.wg.Add(1)
sessionNum++
go server.startSession(sessionNum, &mockConn{serverConn})
go server.startSession(context.Background(), sessionNum, &mockConn{serverConn})
return clientConn
}

View File

@@ -120,7 +120,7 @@ func (s *Server) serve(ctx context.Context) {
} else {
tempDelay = 0
s.wg.Add(1)
go s.startSession(sid, conn)
go s.startSession(ctx, sid, conn)
}
}
}

View File

@@ -300,7 +300,7 @@ func (s *Session) greetHandler(cmd string, arg string) {
s.send("250-" + readyBanner)
s.send("250-8BITMIME")
s.send("250-AUTH PLAIN LOGIN")
if s.Server.config.TLSEnabled && !s.Server.config.ForceTLS && s.Server.tlsConfig != nil && s.tlsState == nil {
if s.config.TLSEnabled && !s.config.ForceTLS && s.tlsConfig != nil && s.tlsState == nil {
s.send("250-STARTTLS")
}
s.send(fmt.Sprintf("250 SIZE %v", s.config.MaxMessageBytes))
@@ -338,7 +338,7 @@ func (s *Session) passwordHandler() {
func (s *Session) readyHandler(cmd string, arg string) {
switch cmd {
case "STARTTLS":
if !s.Server.config.TLSEnabled {
if !s.config.TLSEnabled {
// Invalid command since TLS unconfigured.
s.logger.Debug().Msgf("454 TLS unavailable on the server")
s.send("454 TLS unavailable on the server")
@@ -354,7 +354,7 @@ func (s *Session) readyHandler(cmd string, arg string) {
// Start TLS connection handshake.
s.send("220 STARTTLS")
tlsConn := tls.Server(s.conn, s.Server.tlsConfig)
tlsConn := tls.Server(s.conn, s.tlsConfig)
s.conn = tlsConn
s.text = textproto.NewConn(s.conn)
s.tlsState = new(tls.ConnectionState)
@@ -411,18 +411,6 @@ func (s *Session) parseMailFromCmd(arg string) {
from := m[1]
s.logger.Debug().Msgf("Mail sender is %v", from)
// Parse from address.
_, domain, err := policy.ParseEmailAddress(from)
s.logger.Debug().Msgf("Origin domain is %v", domain)
if from != "" && err != nil {
s.send("501 Bad sender address syntax")
s.logger.Warn().Msgf("Bad address as MAIL arg: %q, %s", from, err)
return
}
if from == "" {
from = "unspecified"
}
// Parse ESMTP parameters.
if m[2] != "" {
// Here the client may put BODY=8BITMIME, but Inbucket already
@@ -480,7 +468,7 @@ func (s *Session) parseMailFromCmd(arg string) {
// Ignore ShouldAccept if extensions explicitly allowed this From.
if extAction == event.ActionDefer && !s.from.ShouldAccept() {
s.send("501 Unauthorized domain")
s.logger.Warn().Msgf("Bad domain sender %s", domain)
s.logger.Warn().Msgf("Bad domain sender %s", origin.Domain)
return
}

View File

@@ -78,6 +78,11 @@ func TestGreetState(t *testing.T) {
}
}
// Messages sent with a null reverse-path are unusual,
// but valid. They are used for delivery status
// notifications, and also for some sorts of auto-responder
// as part of bounce storm mitigation.
// Sections 3.6.3 and 4.5.5 of RFC 5321 discuss them.
func TestEmptyEnvelope(t *testing.T) {
ds := test.NewStore()
server := setupSMTPServer(ds, extension.NewHost())
@@ -85,14 +90,14 @@ func TestEmptyEnvelope(t *testing.T) {
// Test out some empty envelope without blanks
script := []scriptStep{
{"HELO localhost", 250},
{"MAIL FROM:<>", 501},
{"MAIL FROM:<>", 250},
}
playSession(t, server, script)
// Test out some empty envelope with blanks
script = []scriptStep{
{"HELO localhost", 250},
{"MAIL FROM: <>", 501},
{"MAIL FROM: <>", 250},
}
playSession(t, server, script)
}
@@ -450,7 +455,6 @@ func TestBeforeMailFromAcceptedEventResponse(t *testing.T) {
}
for name, tc := range tcs {
tc := tc
t.Run(name, func(t *testing.T) {
// Reset event listener.
shouldReturn = &tc.eventRes
@@ -619,7 +623,6 @@ func TestBeforeRcptToAcceptedEventResponse(t *testing.T) {
}
for name, tc := range tcs {
tc := tc
t.Run(name, func(t *testing.T) {
// Reset event listener.
shouldReturn = &tc.eventRes

View File

@@ -130,6 +130,11 @@ func NewServer(conf *config.Root, mm message.Manager, mh *msghub.Hub) *Server {
// Start begins listening for HTTP requests
func (s *Server) Start(ctx context.Context, readyFunc func()) {
var (
err error
listenCfg net.ListenConfig
)
server = &http.Server{
Addr: rootConfig.Web.Addr,
Handler: requestLoggingWrapper(Router),
@@ -140,8 +145,11 @@ func (s *Server) Start(ctx context.Context, readyFunc func()) {
// We don't use ListenAndServe because it lacks a way to close the listener
log.Info().Str("module", "web").Str("phase", "startup").Str("addr", server.Addr).
Msg("HTTP listening on tcp4")
var err error
listener, err = net.Listen("tcp", server.Addr)
// This context is only used while the listener is resolving our address.
listenCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
listener, err = listenCfg.Listen(listenCtx, "tcp", server.Addr)
if err != nil {
log.Error().Str("module", "web").Str("phase", "startup").Err(err).
Msg("HTTP failed to start TCP4 listener")

View File

@@ -37,7 +37,7 @@ func TestMaxSize(t *testing.T) {
for _, mailbox := range boxes {
go func(mailbox string) {
size := int64(0)
for i := 0; i < n; i++ {
for range n {
_, nbytes := test.DeliverToStore(t, s, mailbox, "subject", time.Now())
size += nbytes
}

View File

@@ -70,7 +70,7 @@ func (m *ManagerStub) MarkSeen(mailbox, id string) error {
}
for _, msg := range m.mailboxes[mailbox] {
if msg.ID == id {
msg.MessageMetadata.Seen = true
msg.Seen = true
return nil
}
}

View File

@@ -139,7 +139,7 @@ func testMetadata(s storeSuite) {
// testContent generates some binary content and makes sure it is correctly retrieved.
func testContent(s storeSuite) {
content := make([]byte, 5000)
for i := 0; i < len(content); i++ {
for i := range content {
content[i] = byte(i % 256)
}
mailbox := "testmailbox"
@@ -379,7 +379,7 @@ func testPurge(s storeSuite) {
}
gotEvents = append(gotEvents, ev)
}
assert.Equal(s, len(subjects), len(gotEvents),
assert.Len(s, gotEvents, len(subjects),
"expected delete event for each message in mailbox")
}
@@ -388,7 +388,7 @@ func testMsgCap(s storeSuite) {
mbCap := 10
mailbox := "captain"
for i := 0; i < 20; i++ {
for i := range 20 {
subj := fmt.Sprintf("subject %v", i)
DeliverToStore(s.T, s.store, mailbox, subj, time.Now())
msgs, err := s.store.GetMessages(mailbox)
@@ -401,10 +401,7 @@ func testMsgCap(s storeSuite) {
}
// Check that the first (oldest) message is correct.
first := i - mbCap + 1
if first < 0 {
first = 0
}
first := max(i-mbCap+1, 0)
firstSubj := fmt.Sprintf("subject %v", first)
if firstSubj != msgs[0].Subject() {
s.Errorf("Got subject %q, wanted first subject: %q", msgs[0].Subject(), firstSubj)
@@ -415,7 +412,7 @@ func testMsgCap(s storeSuite) {
// testNoMsgCap verfies a cap of 0 is not enforced.
func testNoMsgCap(s storeSuite) {
mailbox := "captain"
for i := 0; i < 20; i++ {
for i := range 20 {
subj := fmt.Sprintf("subject %v", i)
DeliverToStore(s.T, s.store, mailbox, subj, time.Now())
GetAndCountMessages(s.T, s.store, mailbox, i+1)

View File

@@ -31,7 +31,6 @@ func TestStoreStubMailboxAddGetVisit(t *testing.T) {
{mailbox: "box3", count: 3},
}
for _, tc := range tcs {
tc := tc
t.Run(tc.mailbox, func(t *testing.T) {
var err error

View File

@@ -2,7 +2,7 @@ Mailbox: recipient
From: <fromuser@inbucket.org>
To: [<recipient@inbucket.org>]
Subject: basic subject
Size: 204
Size: 242
BODY TEXT:
Basic message.

View File

@@ -2,7 +2,7 @@ Mailbox: recipient
From: X-äéß Y-äéß <fromuser@inbucket.org>
To: [Test of ȇɲʢȯȡɪɴʛ <recipient@inbucket.org>]
Subject: Test of ȇɲʢȯȡɪɴʛ
Size: 338
Size: 376
BODY TEXT:
Basic message.

View File

@@ -2,7 +2,7 @@ Mailbox: recipient
From: From User <fromuser@inbucket.org>
To: [Rec I. Pient <recipient@inbucket.org>]
Subject: basic subject
Size: 233
Size: 271
BODY TEXT:
Basic message.

View File

@@ -2,7 +2,7 @@ Mailbox: ip4recipient
From: <fromuser@inbucket.org>
To: [<ip4recipient@[192.168.123.123]>]
Subject: basic subject
Size: 180
Size: 218
BODY TEXT:
No-To message.

View File

@@ -2,7 +2,7 @@ Mailbox: ip6recipient
From: <fromuser@inbucket.org>
To: [<ip6recipient@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]>]
Subject: basic subject
Size: 180
Size: 218
BODY TEXT:
No-To message.

View File

@@ -1,4 +1,6 @@
{ pkgs ? import <nixpkgs> { } }:
{
pkgs ? import <nixpkgs> { },
}:
let
scripts = {
# Quick test script.
@@ -22,7 +24,7 @@ pkgs.mkShell {
elmPackages.elm-json
elmPackages.elm-language-server
elmPackages.elm-test
go_1_21
go_1_25
golangci-lint
golint
gopls

View File

@@ -1016,9 +1016,9 @@ balanced-match@^1.0.0:
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base-x@^3.0.8:
version "3.0.9"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320"
integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==
version "3.0.11"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.11.tgz#40d80e2a1aeacba29792ccc6c5354806421287ff"
integrity sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==
dependencies:
safe-buffer "^5.0.1"
@@ -1578,9 +1578,9 @@ js-tokens@^4.0.0:
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
version "4.1.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b"
integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==
dependencies:
argparse "^2.0.1"