dkim
This commit is contained in:
53
README.md
53
README.md
@@ -56,7 +56,7 @@ You can find default values in [config/defaults.go](config/defaults.go)
|
||||
|
||||
The following configuration needed only if you want to send emails using postmoogle
|
||||
|
||||
First, add new DMARC DNS record of `TXT` type for subdomain `_dmarc` with a proper policy, the easiest one is: `v=DMARC1; p=quarantine;`.
|
||||
**First**, add new DMARC DNS record of `TXT` type for subdomain `_dmarc` with a proper policy, the easiest one is: `v=DMARC1; p=quarantine;`.
|
||||
|
||||
<details>
|
||||
<summary>Example</summary>
|
||||
@@ -86,7 +86,7 @@ _dmarc.DOMAIN. 1799 IN TXT "v=DMARC1; p=quarantine;"
|
||||
|
||||
</details>
|
||||
|
||||
Second, add new SPF DNS record of `TXT` type for your domain that will be used with postmoogle, with format: `v=spf1 ip4:SERVER_IP -all`
|
||||
**Second**, add new SPF DNS record of `TXT` type for your domain that will be used with postmoogle, with format: `v=spf1 ip4:SERVER_IP -all`
|
||||
|
||||
<details>
|
||||
<summary>Example</summary>
|
||||
@@ -116,6 +116,52 @@ DOMAIN. 1799 IN TXT "v=spf1 ip4:111.111.111.111 -all"
|
||||
|
||||
</details>
|
||||
|
||||
**Third**, add new DKIM DNS record of `TXT` type for subdomain `postmoogle._domainkey` that will be used with postmoogle.
|
||||
|
||||
You can get that signature using the `!pm dkim` command:
|
||||
|
||||
<details>
|
||||
<summary>!pm dkim</summary>
|
||||
DKIM signature is: `v=DKIM1; k=ed25519; p=OcVzOwAONDfgbJX/5vwzlXOs9gUDO0YKlXHaDnBJtXw=`.
|
||||
You need to add it to your DNS records (if not already):
|
||||
Add new DNS record with type = `TXT`, key (subdomain/from): `postmoogle._domainkey` and value (to):
|
||||
|
||||
```
|
||||
v=DKIM1; k=ed25519; p=OcVzOwAONDfgbJX/5vwzlXOs9gUDO0YKlXHaDnBJtXw=
|
||||
```
|
||||
|
||||
Without that record other email servers may reject your emails as spam, kupo.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Example</summary>
|
||||
|
||||
```bash
|
||||
$ dig TXT postmoogle._domainkey.DOMAIN
|
||||
|
||||
; <<>> DiG 9.18.6 <<>> TXT postmoogle._domainkey.DOMAIN
|
||||
;; global options: +cmd
|
||||
;; Got answer:
|
||||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59014
|
||||
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
|
||||
|
||||
;; OPT PSEUDOSECTION:
|
||||
; EDNS: version: 0, flags:; udp: 1232
|
||||
;; QUESTION SECTION:
|
||||
;postmoogle._domainkey.DOMAIN. IN TXT
|
||||
|
||||
;; ANSWER SECTION:
|
||||
postmoogle._domainkey.DOMAIN. 600 IN TXT "v=DKIM1; k=ed25519; p=OcVzOwAONDfgbJX/5vwzlXOs9gUDO0YKlXHaDnBJtXw="
|
||||
|
||||
;; Query time: 90 msec
|
||||
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
|
||||
;; WHEN: Mon Sep 05 16:16:21 EEST 2022
|
||||
;; MSG SIZE rcvd: 525
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Usage
|
||||
|
||||
### How to start
|
||||
@@ -147,8 +193,9 @@ If you want to change them - check available options in the help message (`!pm h
|
||||
|
||||
---
|
||||
|
||||
* **!pm mailboxes** - Show the list of all mailboxes
|
||||
* **!pm dkim** - Get DKIM signature
|
||||
* **!pm users** - Get or set allowed users patterns
|
||||
* **!pm mailboxes** - Show the list of all mailboxes
|
||||
* **!pm delete** <mailbox> - Delete specific mailbox
|
||||
|
||||
</details>
|
||||
|
||||
@@ -15,6 +15,7 @@ const (
|
||||
commandHelp = "help"
|
||||
commandStop = "stop"
|
||||
commandSend = "send"
|
||||
commandDKIM = "dkim"
|
||||
commandUsers = botOptionUsers
|
||||
commandDelete = "delete"
|
||||
commandMailboxes = "mailboxes"
|
||||
@@ -132,6 +133,11 @@ func (b *Bot) initCommands() commandList {
|
||||
description: "Get or set allowed users",
|
||||
allowed: b.allowAdmin,
|
||||
},
|
||||
{
|
||||
key: commandDKIM,
|
||||
description: "Get DKIM signature",
|
||||
allowed: b.allowAdmin,
|
||||
},
|
||||
{
|
||||
key: commandMailboxes,
|
||||
description: "Show the list of all mailboxes",
|
||||
@@ -163,6 +169,8 @@ func (b *Bot) handleCommand(ctx context.Context, evt *event.Event, commandSlice
|
||||
b.runStop(ctx)
|
||||
case commandSend:
|
||||
b.runSend(ctx, commandSlice)
|
||||
case commandDKIM:
|
||||
b.runDKIM(ctx)
|
||||
case commandUsers:
|
||||
b.runUsers(ctx, commandSlice)
|
||||
case commandDelete:
|
||||
@@ -272,7 +280,6 @@ func (b *Bot) runSend(ctx context.Context, commandSlice []string) {
|
||||
subject := lines[1]
|
||||
body := strings.Join(lines[2:], "\n")
|
||||
|
||||
b.log.Debug("to=%s subject=%s body=%s", to, subject, body)
|
||||
err := b.Send2Email(ctx, to, subject, body)
|
||||
if err != nil {
|
||||
b.Error(ctx, evt.RoomID, "cannot send email: %v", err)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"gitlab.com/etke.cc/go/secgen"
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"gitlab.com/etke.cc/postmoogle/utils"
|
||||
@@ -130,3 +131,32 @@ func (b *Bot) runUsers(ctx context.Context, commandSlice []string) {
|
||||
b.allowedUsers = allowedUsers
|
||||
b.SendNotice(ctx, evt.RoomID, "allowed users updated")
|
||||
}
|
||||
|
||||
func (b *Bot) runDKIM(ctx context.Context) {
|
||||
evt := eventFromContext(ctx)
|
||||
cfg := b.getBotSettings()
|
||||
signature := cfg.DKIMSignature()
|
||||
if signature == "" {
|
||||
var private string
|
||||
var derr error
|
||||
signature, private, derr = secgen.DKIM()
|
||||
if derr != nil {
|
||||
b.Error(ctx, evt.RoomID, "cannot generate DKIM signature: %v", derr)
|
||||
return
|
||||
}
|
||||
cfg.Set(botOptionDKIMSignature, signature)
|
||||
cfg.Set(botOptionDKIMPrivateKey, private)
|
||||
err := b.setBotSettings(cfg)
|
||||
if err != nil {
|
||||
b.Error(ctx, evt.RoomID, "cannot save bot options: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
b.SendNotice(ctx, evt.RoomID, fmt.Sprintf(
|
||||
"DKIM signature is: `%s`.\n"+
|
||||
"You need to add it to your DNS records (if not already):\n"+
|
||||
"Add new DNS record with type = `TXT`, key (subdomain/from): `postmoogle._domainkey` and value (to):\n ```\n%s\n```\n"+
|
||||
"Without that record other email servers may reject your emails as spam, kupo.",
|
||||
signature, signature))
|
||||
}
|
||||
|
||||
40
bot/email.go
40
bot/email.go
@@ -2,11 +2,15 @@ package bot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/emersion/go-msgauth/dkim"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/format"
|
||||
"maunium.net/go/mautrix/id"
|
||||
@@ -234,9 +238,45 @@ func (b *Bot) Send2Email(ctx context.Context, to, subject, body string) error {
|
||||
msg.WriteString(body)
|
||||
msg.WriteString("\r\n")
|
||||
|
||||
msg = b.signDKIM(msg)
|
||||
|
||||
return b.mta.Send(from, to, msg.String())
|
||||
}
|
||||
|
||||
func (b *Bot) signDKIM(body strings.Builder) strings.Builder {
|
||||
privkey := b.getBotSettings().DKIMPrivateKey()
|
||||
if privkey == "" {
|
||||
b.log.Warn("DKIM private key not found, email will be sent unsigned")
|
||||
return body
|
||||
}
|
||||
pemblock, _ := pem.Decode([]byte(privkey))
|
||||
if pemblock == nil {
|
||||
b.log.Error("cannot decode DKIM private key")
|
||||
return body
|
||||
}
|
||||
parsedkey, err := x509.ParsePKCS8PrivateKey(pemblock.Bytes)
|
||||
if err != nil {
|
||||
b.log.Error("cannot parse PKCS8 private key: %v", err)
|
||||
return body
|
||||
}
|
||||
signer := parsedkey.(crypto.Signer)
|
||||
|
||||
options := &dkim.SignOptions{
|
||||
Domain: b.domain,
|
||||
Selector: "postmoogle",
|
||||
Signer: signer,
|
||||
}
|
||||
|
||||
var msg strings.Builder
|
||||
err = dkim.Sign(&msg, strings.NewReader(body.String()), options)
|
||||
if err != nil {
|
||||
b.log.Error("cannot sign email: %v", err)
|
||||
return body
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
func (b *Bot) sendFiles(ctx context.Context, roomID id.RoomID, files []*utils.File, noThreads bool, parentID id.EventID) {
|
||||
for _, file := range files {
|
||||
req := file.Convert()
|
||||
|
||||
@@ -11,7 +11,9 @@ const acBotSettingsKey = "cc.etke.postmoogle.config"
|
||||
|
||||
// bot options keys
|
||||
const (
|
||||
botOptionUsers = "users"
|
||||
botOptionUsers = "users"
|
||||
botOptionDKIMSignature = "dkim.pub"
|
||||
botOptionDKIMPrivateKey = "dkim.pem"
|
||||
)
|
||||
|
||||
type botSettings map[string]string
|
||||
@@ -40,6 +42,16 @@ func (s botSettings) Users() []string {
|
||||
return []string{value}
|
||||
}
|
||||
|
||||
// DKIMSignature (DNS TXT record)
|
||||
func (s botSettings) DKIMSignature() string {
|
||||
return s.Get(botOptionDKIMSignature)
|
||||
}
|
||||
|
||||
// DKIMPrivateKey keep it secret
|
||||
func (s botSettings) DKIMPrivateKey() string {
|
||||
return s.Get(botOptionDKIMPrivateKey)
|
||||
}
|
||||
|
||||
func (b *Bot) initBotUsers() ([]string, error) {
|
||||
config := b.getBotSettings()
|
||||
cfgUsers := config.Users()
|
||||
|
||||
3
go.mod
3
go.mod
@@ -4,6 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
git.sr.ht/~xn/cache/v2 v2.0.0
|
||||
github.com/emersion/go-msgauth v0.6.6
|
||||
github.com/emersion/go-smtp v0.15.0
|
||||
github.com/getsentry/sentry-go v0.13.0
|
||||
github.com/jhillyerd/enmime v0.10.0
|
||||
@@ -11,6 +12,7 @@ require (
|
||||
github.com/mattn/go-sqlite3 v1.14.14
|
||||
gitlab.com/etke.cc/go/env v1.0.0
|
||||
gitlab.com/etke.cc/go/logger v1.1.0
|
||||
gitlab.com/etke.cc/go/secgen v1.1.0
|
||||
gitlab.com/etke.cc/linkpearl v0.0.0-20220831124140-598117f26c77
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
|
||||
maunium.net/go/mautrix v0.12.0
|
||||
@@ -27,6 +29,7 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.12 // indirect
|
||||
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
|
||||
19
go.sum
19
go.sum
@@ -6,10 +6,18 @@ github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXO
|
||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emersion/go-message v0.11.2/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY=
|
||||
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
|
||||
github.com/emersion/go-milter v0.3.3/go.mod h1:ablHK0pbLB83kMFBznp/Rj8aV+Kc3jw8cxzzmCNLIOY=
|
||||
github.com/emersion/go-msgauth v0.6.6 h1:buv5lL8v/3v4RpHnQFS2IPhE3nxSRX+AxnrEJbDbHhA=
|
||||
github.com/emersion/go-msgauth v0.6.6/go.mod h1:A+/zaz9bzukLM6tRWRgJ3BdrBi+TFKTvQ3fGMFOI9SM=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||
github.com/emersion/go-smtp v0.15.0 h1:3+hMGMGrqP/lqd7qoxZc1hTU8LY8gHV9RFGWlqSDmP8=
|
||||
github.com/emersion/go-smtp v0.15.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||
github.com/getsentry/sentry-go v0.13.0 h1:20dgTiUSfxRB/EhMPtxcL9ZEbM1ZdR+W/7f7NWD+xWo=
|
||||
github.com/getsentry/sentry-go v0.13.0/go.mod h1:EOsfu5ZdvKPfeHYV6pTVQnsjfp30+XA7//UooKNumH0=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
@@ -30,6 +38,7 @@ github.com/jhillyerd/enmime v0.10.0 h1:DZEzhptPRBesvN3gf7K1BOh4rfpqdsdrEoxW1Edr/
|
||||
github.com/jhillyerd/enmime v0.10.0/go.mod h1:Qpe8EEemJMFAF8+NZoWdpXvK2Yb9dRF0k/z6mkcDHsA=
|
||||
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
|
||||
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/martinlindhe/base36 v1.0.0/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
@@ -41,6 +50,8 @@ github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxm
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
|
||||
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a h1:eU8j/ClY2Ty3qdHnn0TyW3ivFoPC/0F1gQZz8yTxbbE=
|
||||
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a/go.mod h1:v8eSC2SMp9/7FTKUncp7fH9IwPfw+ysMObcEz5FWheQ=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||
@@ -57,6 +68,7 @@ github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6us
|
||||
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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
@@ -74,21 +86,28 @@ gitlab.com/etke.cc/go/env v1.0.0 h1:J98BwzOuELnjsVPFvz5wa79L7IoRV9CmrS41xLYXtSw=
|
||||
gitlab.com/etke.cc/go/env v1.0.0/go.mod h1:e1l4RM5MA1sc0R1w/RBDAESWRwgo5cOG9gx8BKUn2C4=
|
||||
gitlab.com/etke.cc/go/logger v1.1.0 h1:Yngp/DDLmJ0jJNLvLXrfan5Gi5QV+r7z6kCczTv8t4U=
|
||||
gitlab.com/etke.cc/go/logger v1.1.0/go.mod h1:8Vw5HFXlZQ5XeqvUs5zan+GnhrQyYtm/xe+yj8H/0zk=
|
||||
gitlab.com/etke.cc/go/secgen v1.1.0 h1:KFjFEXNlSPtY19ichNL+lQF2Q0vP3/9O2rVGZzVrqq0=
|
||||
gitlab.com/etke.cc/go/secgen v1.1.0/go.mod h1:3pJqRGeWApzx7qXjABqz2o2SMCNpKSZao/gXVdasqE8=
|
||||
gitlab.com/etke.cc/linkpearl v0.0.0-20220831124140-598117f26c77 h1:O9t4Sw/nu0JDUX+3KYjaqBi887opyNZ0imE+i2sV+q8=
|
||||
gitlab.com/etke.cc/linkpearl v0.0.0-20220831124140-598117f26c77/go.mod h1:CqwzwxVogKG6gDWTPTen3NyWbTESg42jxoTfXXwDGKQ=
|
||||
golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20210501142056-aec3718b3fa0/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
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=
|
||||
|
||||
Reference in New Issue
Block a user