Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.21.x, 1.22.x, 1.23.x]
go-version: [1.23.x, 1.24.x]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -19,8 +19,8 @@ jobs:
go-version: ${{ matrix.go-version }}
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v8
with:
version: v1.63
version: latest
- run: go vet ./...
- run: go test -tags skipsecretserviceintegrationtests ./...
109 changes: 100 additions & 9 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,104 @@
linters-settings:
gocritic:
disabled-checks:
- ifElseChain
- elseif

linters:
formatters:
enable:
- gofmt
exclusions:
paths:
- .*_mock\.go
- mock_.*\.go
- .*/pkg/mod/.*$
- .*/go/src/.*\.go
- third_party$
- builtin$
- examples$
settings:
gofmt:
simplify: true
goimports:
local-prefixes:
- go.opentelemetry.io
issues:
max-issues-per-linter: 50
linters:
default: none
enable:
- asciicheck
- bodyclose
- dogsled
- durationcheck
- errcheck
- errorlint
- exhaustive
- forbidigo
- forcetypeassert
- goconst
- gocritic
- unconvert
- revive
- gocyclo
- godot
- gosec
- govet
- ineffassign
- misspell
- nestif
- nilerr
- nlreturn
- noctx
- prealloc
- predeclared
- revive
- sqlclosecheck
- staticcheck
- unconvert
- unused
- whitespace
- wrapcheck
- wsl_v5
exclusions:
paths:
- .*_mock\.go
- mock_.*\.go
- .*/pkg/mod/.*$
- .*/go/src/.*\.go
- third_party$
- builtin$
- examples$
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
settings:
depguard:
rules:
main:
allow:
- $all
dupl:
threshold: 99
errcheck:
check-blank: false
check-type-assertions: false
goconst:
min-len: 3
min-occurrences: 2
gocyclo:
min-complexity: 18
govet:
disable:
- shadow
misspell:
ignore-rules:
- cancelled
locale: US
revive:
severity: warning
output:
formats:
text:
path: stdout
print-issued-lines: true
print-linter-name: true
run:
concurrency: 4
issues-exit-code: 1
tests: false
version: "2"
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
The MIT License (MIT)

Copyright (c) 2015 Keybase
Copyright (c) 2025 Mailstone

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -19,4 +20,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Go Keychain

[![Build Status](https://github.com/keybase/go-keychain/actions/workflows/ci.yml/badge.svg)](https://github.com/keybase/go-keychain/actions)
[![Build Status](https://github.com/mailstone/go-keychain/actions/workflows/ci.yml/badge.svg)](https://github.com/mailstone/go-keychain/actions)

A library for accessing the Keychain for macOS, iOS, and Linux in Go (golang).

Requires macOS 10.9 or greater and iOS 8 or greater. On Linux, communicates to
a provider of the DBUS SecretService spec like gnome-keyring or ksecretservice.

```go
import "github.com/keybase/go-keychain"
import "github.com/mailstone/go-keychain"
```

## Mac/iOS Usage
Expand Down
30 changes: 20 additions & 10 deletions bind/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,40 @@
package bind

import (
"errors"
"fmt"
"reflect"

"github.com/keybase/go-keychain"
"github.com/mailstone/go-keychain"
)

// Test is a bind interface for the test
// Test is a bind interface for the test.
type Test interface {
Fail(s string)
}

// AddGenericPassword adds generic password
// AddGenericPassword adds generic password.
func AddGenericPassword(service string, account string, label string, password string, accessGroup string) error {
item := keychain.NewGenericPassword(service, account, label, []byte(password), accessGroup)
return keychain.AddItem(item)

return keychain.AddItem(item) // nolint: wrapcheck
}

// DeleteGenericPassword deletes generic password
// DeleteGenericPassword deletes generic password.
func DeleteGenericPassword(service string, account string, accessGroup string) error {
item := keychain.NewItem()
item.SetSecClass(keychain.SecClassGenericPassword)
item.SetService(service)
item.SetAccount(account)
item.SetAccessGroup(accessGroup)
return keychain.DeleteItem(item)

return keychain.DeleteItem(item) // nolint: wrapcheck
}

// GenericPasswordTest runs test code for generic password keychain item.
// This is here so we can export using gomobile bind and run this method on iOS simulator and device.
// Access groups aren't supported in iOS simulator.
// nolint: gocyclo
func GenericPasswordTest(t Test, service string, accessGroup string) {
var err error

Expand All @@ -54,6 +58,7 @@ func GenericPasswordTest(t Test, service string, accessGroup string) {
if err != nil {
t.Fail(err.Error())
}

if len(accounts) != 0 {
t.Fail("Should have no accounts")
}
Expand All @@ -66,7 +71,7 @@ func GenericPasswordTest(t Test, service string, accessGroup string) {

// Test dupe
err = keychain.AddItem(item)
if err != keychain.ErrorDuplicateItem {
if !errors.Is(err, keychain.ErrorDuplicateItem) {
t.Fail("Should error with duplicate item")
}

Expand All @@ -84,6 +89,7 @@ func GenericPasswordTest(t Test, service string, accessGroup string) {
query.SetAccessGroup(accessGroup)
query.SetMatchLimit(keychain.MatchLimitAll)
query.SetReturnAttributes(true)

results, err := keychain.QueryItem(query)
if err != nil {
t.Fail(err.Error())
Expand Down Expand Up @@ -113,6 +119,7 @@ func GenericPasswordTest(t Test, service string, accessGroup string) {
queryData.SetAccessGroup(accessGroup)
queryData.SetMatchLimit(keychain.MatchLimitOne)
queryData.SetReturnData(true)

resultsData, err := keychain.QueryItem(queryData)
if err != nil {
t.Fail(err.Error())
Expand All @@ -131,6 +138,7 @@ func GenericPasswordTest(t Test, service string, accessGroup string) {
if err != nil {
t.Fail(err.Error())
}

if len(accounts2) != 2 {
t.Fail(fmt.Sprintf("Should have 2 accounts: %v", accounts2))
}
Expand All @@ -145,8 +153,8 @@ func GenericPasswordTest(t Test, service string, accessGroup string) {
queryDel.SetService(service)
queryDel.SetAccount(account)
queryDel.SetAccessGroup(accessGroup)
err = keychain.DeleteItem(queryDel)
if err != nil {

if err := keychain.DeleteItem(queryDel); err != nil {
t.Fail(err.Error())
}

Expand All @@ -158,6 +166,7 @@ func GenericPasswordTest(t Test, service string, accessGroup string) {
query3.SetAccessGroup(accessGroup)
query3.SetMatchLimit(keychain.MatchLimitAll)
query3.SetReturnAttributes(true)

results3, err := keychain.QueryItem(query3)
if err != nil {
t.Fail(err.Error())
Expand All @@ -171,13 +180,14 @@ func GenericPasswordTest(t Test, service string, accessGroup string) {
if err != nil {
t.Fail(err.Error())
}

if len(accounts3) != 1 {
t.Fail("Should have an account")
}

// Test remove not found
err = keychain.DeleteItem(item)
if err != keychain.ErrorItemNotFound {
if !errors.Is(err, keychain.ErrorItemNotFound) {
t.Fail("Error should be not found")
}
}
2 changes: 1 addition & 1 deletion bindtest/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package bindtest
import (
"testing"

"github.com/keybase/go-keychain/bind"
"github.com/mailstone/go-keychain/bind"
"github.com/stretchr/testify/require"
)

Expand Down
Loading