Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • integration-test
  • master
  • memguard
  • pass-state
  • renovate/git.autistici.org-ai3-go-common-digest
  • renovate/git.autistici.org-id-go-sso-digest
  • renovate/github.com-go-ldap-ldap-v3-3.x
  • renovate/github.com-go-sql-driver-mysql-1.x
  • renovate/github.com-lib-pq-1.x
  • renovate/github.com-mattn-go-sqlite3-1.x
  • renovate/github.com-prometheus-client_golang-1.x
  • renovate/golang.org-x-crypto-0.x
  • renovate/golang.org-x-sync-0.x
13 results

Target

Select target project
  • id/keystore
1 result
Select Git revision
  • integration-test
  • master
  • memguard
  • pass-state
  • renovate/git.autistici.org-ai3-go-common-digest
  • renovate/git.autistici.org-id-go-sso-digest
  • renovate/github.com-go-ldap-ldap-v3-3.x
  • renovate/github.com-go-sql-driver-mysql-1.x
  • renovate/github.com-lib-pq-1.x
  • renovate/github.com-mattn-go-sqlite3-1.x
  • renovate/github.com-prometheus-client_golang-1.x
  • renovate/golang.org-x-crypto-0.x
  • renovate/golang.org-x-sync-0.x
13 results
Show changes
Commits on Source (12)
include: "https://git.autistici.org/ai3/build-deb/raw/master/ci-common.yml"
include:
- "https://git.autistici.org/pipelines/debian/raw/master/common.yml"
- "https://git.autistici.org/pipelines/images/test/golang/raw/master/ci.yml"
......@@ -5,7 +5,9 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"strconv"
"git.autistici.org/ai3/go-common/unix"
)
......@@ -15,6 +17,11 @@ var (
noMatchResponse = []byte{'N', '\n'}
)
const (
supportedDictProtocolVersionMin = 2
supportedDictProtocolVersionMax = 3
)
// DictDatabase is an interface to a key/value store by way of the Lookup
// method.
type DictDatabase interface {
......@@ -25,7 +32,7 @@ type DictDatabase interface {
}
// DictProxyServer exposes a Database using the Dovecot dict proxy
// protocol (see https://wiki2.dovecot.org/AuthDatabase/Dict).
// protocol (see https://doc.dovecot.org/developer_manual/design/dict_protocol/).
//
// It implements the unix.LineHandler interface from the
// ai3/go-common/unix package.
......@@ -55,12 +62,35 @@ func (p *DictProxyServer) ServeLine(ctx context.Context, lw unix.LineResponseWri
}
func (p *DictProxyServer) handleHello(ctx context.Context, lw unix.LineResponseWriter, arg []byte) error {
// TODO: parse the hello line and extract useful information.
fields := splitFields(arg)
if len(fields) < 1 {
return errors.New("could not parse HELLO")
}
majorVersion, _ := strconv.Atoi(string(fields[0]))
if majorVersion < supportedDictProtocolVersionMin || majorVersion > supportedDictProtocolVersionMax {
return fmt.Errorf("unsupported protocol version %d", majorVersion)
}
// In version 3, HELLO expects a response.
if majorVersion == 3 {
s := fmt.Sprintf("O%d\t0", majorVersion)
return lw.WriteLineCRLF([]byte(s))
}
return nil
}
func (p *DictProxyServer) handleLookup(ctx context.Context, lw unix.LineResponseWriter, arg []byte) error {
obj, ok, err := p.db.Lookup(ctx, string(arg))
// Support protocol versions 2 and 3 by looking for the \t
// field separator, which should not appear in the key in
// version 2 anyway.
fields := splitFields(arg)
if len(fields) < 1 {
return errors.New("could not parse LOOKUP")
}
obj, ok, err := p.db.Lookup(ctx, string(fields[0]))
if err != nil {
log.Printf("error: %v", err)
return lw.WriteLine(failResponse)
......@@ -78,3 +108,41 @@ func (p *DictProxyServer) handleLookup(ctx context.Context, lw unix.LineResponse
//buf.Write([]byte{'\n'})
return lw.WriteLine(buf.Bytes())
}
var dovecotEscapeChars = map[byte]byte{
'0': 0,
'1': 1,
't': '\t',
'r': '\r',
'l': '\n',
}
var fieldSeparator = []byte{'\t'}
func unescapeInplace(b []byte) []byte {
var esc bool
var j int
for i := 0; i < len(b); i++ {
c := b[i]
if esc {
if escC, ok := dovecotEscapeChars[c]; ok {
c = escC
}
esc = false
} else if c == '\001' {
esc = true
continue
}
b[j] = c
j++
}
return b[:j]
}
func splitFields(b []byte) [][]byte {
fields := bytes.Split(b, fieldSeparator)
for i := 0; i < len(fields); i++ {
fields[i] = unescapeInplace(fields[i])
}
return fields
}
package dovecot
import (
"context"
"io/ioutil"
"log"
"net/textproto"
"os"
"path/filepath"
"testing"
"git.autistici.org/ai3/go-common/unix"
)
func TestUnescape(t *testing.T) {
for _, td := range []struct {
input, exp string
}{
{"boo", "boo"},
{"bo\001t", "bo\t"},
{"bo\001t\001l", "bo\t\n"},
{"bo\001t\0011", "bo\t\001"},
} {
out := make([]byte, len(td.input))
copy(out, td.input)
out = unescapeInplace(out)
if string(out) != td.exp {
t.Errorf("unescape('%s') returned '%s', expected '%s'", td.input, out, td.exp)
}
}
}
type testDictDatabase struct {
data map[string]interface{}
}
func (d *testDictDatabase) Lookup(_ context.Context, key string) (interface{}, bool, error) {
value, ok := d.data[key]
return value, ok, nil
}
func newTestDictDatabase() *testDictDatabase {
return &testDictDatabase{
data: map[string]interface{}{
"pass/foo": struct {
Password string `json:"password"`
}{
Password: "bar",
},
},
}
}
func newTestSocketServer(t *testing.T) (string, func()) {
t.Helper()
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
socketPath := filepath.Join(dir, "socket")
lsrv := unix.NewLineServer(
NewDictProxyServer(newTestDictDatabase()))
srv, err := unix.NewUNIXSocketServer(socketPath, lsrv)
if err != nil {
t.Fatal(err)
}
errCh := make(chan error, 1)
go func() {
errCh <- srv.Serve()
}()
return socketPath, func() {
srv.Close()
os.RemoveAll(dir)
if err := <-errCh; err != nil {
log.Printf("unix socket server error: %v", err)
}
}
}
func makeTestRequest(t *testing.T, socketPath string, version int, lookupKey, expected string) {
conn, err := textproto.Dial("unix", socketPath)
if err != nil {
t.Fatalf("dialing socket: %v", err)
}
defer conn.Close()
if err := conn.PrintfLine("H%d\t0\t1\tuser\tpass", version); err != nil {
t.Fatalf("error writing HELLO: %v", err)
}
if version > 2 {
resp, err := conn.ReadLine()
if err != nil {
t.Fatalf("error reading HELLO response: %v", err)
}
if resp[0] != 'O' {
t.Fatalf("request returned unexpected status: %s", resp)
}
}
if err := conn.PrintfLine("L%s", lookupKey); err != nil {
t.Fatalf("error writing LOOKUP: %v", err)
}
resp, err := conn.ReadLine()
if err != nil {
t.Fatalf("error reading HELLO response: %v", err)
}
if resp != expected {
t.Fatalf("unexpected response: got '%s', expected '%s'", resp, expected)
}
}
func TestLookup(t *testing.T) {
socketPath, cleanup := newTestSocketServer(t)
defer cleanup()
makeTestRequest(t, socketPath, 2, "pass/foo", "O{\"password\":\"bar\"}")
makeTestRequest(t, socketPath, 3, "pass/foo", "O{\"password\":\"bar\"}")
makeTestRequest(t, socketPath, 2, "unknown", "N")
makeTestRequest(t, socketPath, 3, "unknown", "N")
}
......@@ -4,7 +4,7 @@ go 1.15
require (
git.autistici.org/ai3/go-common v0.0.0-20221125154433-06304016b1da
git.autistici.org/id/go-sso v0.0.0-20221216110623-a98dfc78fec5
git.autistici.org/id/go-sso v0.0.0-20230822064459-ed921a53bb33
github.com/coreos/go-systemd/v22 v22.5.0
github.com/go-ldap/ldap/v3 v3.4.4
github.com/go-sql-driver/mysql v1.7.0
......@@ -12,5 +12,6 @@ require (
github.com/mattn/go-sqlite3 v1.14.16
github.com/prometheus/client_golang v1.12.2
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/sync v0.3.0
gopkg.in/yaml.v3 v3.0.1
)
This diff is collapsed.
stages:
- test
run_tests:
stage: test
image: registry.git.autistici.org/ai3/docker/test/golang:master
script:
- run-go-test ./...
artifacts:
when: always
reports:
coverage_report:
coverage_format: cobertura
path: cover.xml
junit: report.xml
include: "https://git.autistici.org/pipelines/images/test/golang/raw/master/ci.yml"
......@@ -10,7 +10,7 @@ git.autistici.org/ai3/go-common/serverutil
git.autistici.org/ai3/go-common/tracing
git.autistici.org/ai3/go-common/unix
git.autistici.org/ai3/go-common/userenckey
# git.autistici.org/id/go-sso v0.0.0-20221216110623-a98dfc78fec5
# git.autistici.org/id/go-sso v0.0.0-20230822064459-ed921a53bb33
## explicit
git.autistici.org/id/go-sso
# github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e
......@@ -441,7 +441,8 @@ golang.org/x/oauth2/google/internal/externalaccount
golang.org/x/oauth2/internal
golang.org/x/oauth2/jws
golang.org/x/oauth2/jwt
# golang.org/x/sync v0.1.0
# golang.org/x/sync v0.3.0
## explicit
golang.org/x/sync/singleflight
# golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
golang.org/x/sys/cpu
......