diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 284513b8..2fad73e8 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -17,19 +17,19 @@ runs: using: composite steps: - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: ^1.16 + go-version: ^1.18 - name: Determine artifact output filename id: artifact-name-generator - run: echo "artifact-name=irma-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.os == 'windows' && '.exe' || '' }}" >> $GITHUB_OUTPUT + run: echo "artifact-name=irma-${{ inputs.os }}-${{ inputs.arch }}${{ inputs.os == 'windows' && '.exe' || '' }}" >> $GITHUB_OUTPUT shell: bash - name: Build run: go build -v -a -ldflags '-extldflags "-static"' -o ${{ steps.artifact-name-generator.outputs.artifact-name }} ./irma shell: bash env: - GOOS: ${{ matrix.os }} - GOARCH: ${{ matrix.arch }} + GOOS: ${{ inputs.os }} + GOARCH: ${{ inputs.arch }} CGO_ENABLED: "0" diff --git a/.github/workflows/delivery.yml b/.github/workflows/delivery.yml index e9bcf211..7a8da789 100644 --- a/.github/workflows/delivery.yml +++ b/.github/workflows/delivery.yml @@ -2,17 +2,26 @@ name: Delivery on: push: - tags: [ v* ] + branches: [ master ] + release: + # Note: a current limitation is that when a release is edited after publication, then the Docker tags are not automatically updated. + types: [ published ] permissions: contents: write + packages: write + +# Disable concurrency to prevent that images are tagged in the wrong order. +concurrency: + group: delivery jobs: - ensure-release-present: + prepare: runs-on: ubuntu-latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + outputs: + is-head-master: ${{ steps.is-head-master.outcome == 'success' }} + is-latest-release: ${{ steps.is-latest-release.outcome == 'success' }} steps: - uses: actions/checkout@v3 with: @@ -23,30 +32,76 @@ jobs: run: git branch --contains ${{ github.sha }} | grep -x "* master" shell: bash + - name: Check whether this event is the HEAD of master + continue-on-error: true + id: is-head-master + run: git rev-parse HEAD | grep -x ${{ github.sha }} + shell: bash + - uses: actions/checkout@v3 - name: Check whether version.go contains the new version number + if: github.event_name == 'release' run: cat version.go | grep ${GITHUB_REF_NAME:1} shell: bash - name: Check whether CHANGELOG.md contains the new version number + if: github.event_name == 'release' run: cat CHANGELOG.md | grep "\[${GITHUB_REF_NAME:1}\]" shell: bash - - name: Check whether release is present - id: release-present - run: gh release view ${{ github.ref_name }} + - name: Check whether the release is latest continue-on-error: true + id: is-latest-release + if: github.event_name == 'release' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release view --json tagName --jq .tagName | grep -x ${{ github.event.release.tag_name }} + shell: bash + + build-docker-image: + runs-on: ubuntu-latest + needs: prepare + steps: + - uses: actions/checkout@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Docker image + run: docker build -t ghcr.io/${{ github.repository_owner }}/irma:${{ github.sha }} . + + - name: Tag Docker image (edge) + if: needs.prepare.outputs.is-head-master == 'true' + run: docker tag ghcr.io/${{ github.repository_owner }}/irma:${{ github.sha }} ghcr.io/${{ github.repository_owner }}/irma:edge + + - name: Tag Docker image (version) + if: github.event_name == 'release' + run: docker tag ghcr.io/${{ github.repository_owner }}/irma:${{ github.sha }} ghcr.io/${{ github.repository_owner }}/irma:${{ github.event.release.tag_name }} + + - name: Tag Docker image (latest) + if: needs.prepare.outputs.is-latest-release == 'true' + run: docker tag ghcr.io/${{ github.repository_owner }}/irma:${{ github.sha }} ghcr.io/${{ github.repository_owner }}/irma:latest - - name: Make new release if necessary - if: steps.release-present.outcome == 'failure' - run: gh release create ${{ github.ref_name }} -t "${{ github.ref_name }}" -n "Check CHANGELOG.md in repository." + - name: Push Docker image (edge) + if: needs.prepare.outputs.is-head-master == 'true' + run: docker push ghcr.io/${{ github.repository_owner }}/irma:edge + + - name: Push Docker image (version) + if: github.event_name == 'release' + run: docker push ghcr.io/${{ github.repository_owner }}/irma:${{ github.event.release.tag_name }} + + - name: Tag Docker image (latest) + if: needs.prepare.outputs.is-latest-release == 'true' + run: docker push ghcr.io/${{ github.repository_owner }}/irma:latest build-release-artifact: - needs: ensure-release-present + needs: prepare runs-on: ubuntu-latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} strategy: matrix: os: [ linux, darwin, windows ] @@ -67,4 +122,13 @@ jobs: arch: ${{ matrix.arch }} - name: Upload artifact - run: gh release upload ${{ github.ref_name }} ${{ steps.build.outputs.artifact-name }} + uses: actions/upload-artifact@v3 + with: + name: irma-${{ matrix.os }}-${{ matrix.arch }} + path: ${{ steps.build.outputs.artifact-name }} + + - name: Upload artifact to release + if: github.event_name == 'release' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release upload ${{ github.event.release.tag_name }} ${{ steps.build.outputs.artifact-name }} diff --git a/.github/workflows/status-checks-dockerfile.yml b/.github/workflows/status-checks-dockerfile.yml index 8df2b7e7..5c9e8216 100644 --- a/.github/workflows/status-checks-dockerfile.yml +++ b/.github/workflows/status-checks-dockerfile.yml @@ -2,39 +2,24 @@ name: Status checks (Dockerfile) on: - push: - branches: [ master ] - paths: - - Dockerfile + # Delivery pipeline already runs this on push to master. pull_request: paths: - Dockerfile - schedule: - # Run every monday on 9:00 in the morning (UTC). - - cron: "0 9 * * 1" - # Make it possible to trigger the checks manually. - workflow_dispatch: + +# Building the Dockerfile includes downloading the IRMA schemes. +# Therefore, we only run one check at the time, and we put a limit on the event types triggering this job. +concurrency: + group: dockerfile jobs: - # Building the Dockerfile includes downloading the IRMA schemes. - # Therefore, we only run one check at the time, and we put a limit on the event types triggering this job. - docker-build-all: + docker-build: runs-on: ubuntu-latest - strategy: - max-parallel: 1 - matrix: - # busybox is not working yet. - image: - - "debian:stable" - - "alpine:latest" - - "ubuntu:latest" - - "centos:latest" - - "amazonlinux:latest" steps: - uses: actions/checkout@v3 - name: Build Dockerfile - run: docker build -t privacybydesign/irma:edge --build-arg BASE_IMAGE=${{ matrix.image }} . + run: docker build -t ghcr.io/${{ github.repository_owner }}/irma:${{ github.sha }} . - name: Test Docker image - run: docker run privacybydesign/irma:edge version + run: docker run ghcr.io/${{ github.repository_owner }}/irma:${{ github.sha }} version diff --git a/.github/workflows/status-checks.yml b/.github/workflows/status-checks.yml index f2b83960..79ccb521 100644 --- a/.github/workflows/status-checks.yml +++ b/.github/workflows/status-checks.yml @@ -52,9 +52,9 @@ jobs: - uses: actions/checkout@v3 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: ^1.16 + go-version: ^1.18 - name: Run gofmt # gofmt does not return non-zero exit codes on failure, so we have to check that there are no issues using grep. @@ -75,6 +75,12 @@ jobs: - name: Run misspell run: misspell -error . + - name: Install staticcheck + run: go install honnef.co/go/tools/cmd/staticcheck@2023.1.3 + + - name: Run staticcheck + run: staticcheck -checks "all,-ST1000,-ST1003,-SA1019,-SA1029" ./... + test: runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 75faaa0c..3361111e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,33 +5,61 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +### Added +- E-mail address revalidation, addressing issues where user's e-mail addresses can be (temporary) invalid +- Keyshare server /api/v2/prove/... endpoints for the new keyshare protocol + +## [0.13.2] - 2023-08-22 +### Changed +- Remove mail header 'Content-Transfer-Encoding: binary' + The header gets converted to 'Content-Transfer-Encoding: quoted-printable' causing 'arc=fail (body hash mismatch)' with gmail + +## [0.13.1] - 2023-08-16 +### Fixed +- Invalid amount of arguments in query scan when e-mail revalidation is disabled +## [0.13.0] - 2023-08-10 ### Added - E-mail address revalidation, addressing issues where user's e-mail addresses can be (temporary) invalid +- Publish the Docker image of the `irma` CLI tool on ghcr.io/privacybydesign/irma +- Support for revocation db type `sqlserver` (Microsoft SQL Server) ### Changed - Use separate application user in Dockerfile for entrypoint - Rename RevocationStorage's UpdateLatest function to LatestUpdates. This name better fits its behaviour. The functionality stays the same. - Validate revocation witness before revocation update is applied - RevocationStorage's EnableRevocation function does not return an error anymore if it has been enabled already +- Use a Docker image created from scratch as base for the Dockerfile - Custom WrapErrorPrefix function that respects the error's type +- Log info message of irma.SessionError errors As part of e-mail address revalidation: - `VerifyMXRecord` incorporates a check to see if there is an active network connection -- MyIrma server: `/user` returns an additional field `revalidate_in_progress` in the JSON response body, indicating whether the e-mail address is being revalidated or not +- MyIrma server: `/user` returns an additional field `revalidate_in_progress` in the JSON response body, indicating whether the e-mail address is being revalidated or not - MyIrma server: `/user/delete` and `/email/remove` return a 500 status code and `REVALIDATE_EMAIL` error type if one or more e-mail addresses of the user are invalid **Note:** Enabling e-mail address revalidation requires a change in the database schema. In order to do this please add the `revalidate_on` column of type `bigint` to the `irma.emails` table. See the [schema](https://github.com/privacybydesign/irmago/tree/master/server/keyshare/schema.sql#L50) file. Otherwise e-mail address revalidation is disabled and there will not be a breaking change. ### Fixed - Race conditions in database logic of revocation storage -- `irma scheme verify` not detecting missing files in index +- `irma scheme verify` not detecting missing files in index - Scheme verification/signing does not reject credentials with invalid revocation settings - Write transactions within memory implementation of revocation storage may lead to unintended changes ### Removed - Superfluous openssl package in Dockerfile +### Security +- Let IRMA servers by default reject IRMA/Yivi apps that don't support pairing codes (IRMA protocol version <= 2.7) + +**Note:** This is an important security update for issuers to make sure that pairing codes cannot be circumvented. +IRMA apps that don't support pairing codes should not be in circulation anymore, so this change won't affect users. +Yivi apps have always supported pairing codes. + +### Internal +- Linter switch from golint to staticcheck +- Use Postgres 15 for unit and component tests + ## [0.12.6] - 2023-05-31 ### Fixed - Legacy endpoints of keyshare server return 403 status codes when database is down @@ -378,6 +406,9 @@ This release contains several large new features. In particular, the shoulder su - Combined issuance-disclosure requests with two schemes one of which has a keyshare server now work as expected - Various other bugfixes +[0.13.2]: https://github.com/privacybydesign/irmago/compare/v0.13.1...v0.13.2 +[0.13.1]: https://github.com/privacybydesign/irmago/compare/v0.13.0...v0.13.1 +[0.13.0]: https://github.com/privacybydesign/irmago/compare/v0.12.6...v0.13.0 [0.12.6]: https://github.com/privacybydesign/irmago/compare/v0.12.5...v0.12.6 [0.12.5]: https://github.com/privacybydesign/irmago/compare/v0.12.4...v0.12.5 [0.12.4]: https://github.com/privacybydesign/irmago/compare/v0.12.3...v0.12.4 diff --git a/Dockerfile b/Dockerfile index aec407c8..d4fc9b57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,4 @@ -# Use variable base image, such that we can also build for other base images, like alpine. -ARG BASE_IMAGE=debian:stable-slim - -FROM golang:1 as build +FROM golang:1-alpine as build # Set build environment ENV CGO_ENABLED=0 @@ -11,23 +8,27 @@ COPY . /irmago WORKDIR /irmago RUN go build -a -ldflags '-extldflags "-static"' -o "/bin/irma" ./irma -FROM $BASE_IMAGE +# Create application user +RUN adduser -D -u 1000 -g irma irma -# The amazonlinux image does not include adduser, so we have to install this first. -RUN if grep -q -E 'Amazon Linux' /etc/os-release; then yum install -y shadow-utils; fi +# Start building the final image +FROM scratch -# Add application user -RUN adduser --disabled-password --gecos '' irma || adduser irma +# Copy binary from build stage +COPY --from=build /bin/irma /bin/irma -# The debian image does not include ca-certificates, so we have to install this first. -RUN if which apt-get &> /dev/null; then apt-get update && apt-get install -y ca-certificates; fi +# Add TLS root certificates +COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -COPY --from=build /bin/irma /usr/local/bin/irma +# Ensure the application user and group is set +COPY --from=build /etc/passwd /etc/passwd +COPY --from=build /etc/group /etc/group +COPY --from=build --chown=irma:irma /home/irma/ /home/irma/ # Switch to application user USER irma -# Include schemes in the Docker image to speed up the start-up time. -RUN irma scheme download +# Include schemes in the Docker image to speed up the start-up time +RUN ["/bin/irma", "scheme", "download"] -ENTRYPOINT ["irma"] +ENTRYPOINT ["/bin/irma"] diff --git a/README.md b/README.md index b4952222..8b191c01 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ Technical documentation of all components of `irmago` and more can be found at https://irma.app/docs. -## Running +## Running (development) -The easiest way to run the `irma` command line tool is using Docker. +The easiest way to run the `irma` command line tool for development purposes is using Docker. docker-compose run irma @@ -30,51 +30,41 @@ You can run the `irma keyshare` services locally using the test configuration in docker-compose run -p 8081:8081 irma keyshare myirmaserver -c ./testdata/configurations/myirmaserver.yml ## Installing +### Using Go +To install the latest released version of the `irma` command line tool using Go, you do the following. - git clone https://github.com/privacybydesign/irmago + go install github.com/privacybydesign/irmago/irma@latest -`irmago` and its subpackages use Go modules for their dependencies. The `go` command will automatically download dependencies when needed. +You can also specify an exact version. You should replace `v0.0.0` with the desired version number. + + go install github.com/privacybydesign/irmago/irma@v0.0.0 -To install the `irma` command line tool: +### Using a container +If you want a container image of the `irma` command line tool, then you can use our `ghcr.io/privacybydesign/irma` image. - go install ./irma + docker run ghcr.io/privacybydesign/irma:latest -You can also include the `irma` command line tool in a Docker image, using a base image of your choice. The default base image is Debian's `stable-slim`. +The images are tagged in the following way: +- `latest`: latest released version of `irma` +- `edge`: HEAD of the main development branch (`master`) +- `v0.0.0`: `irma` version (replace `v0.0.0` with the desired version number) - docker build --build-arg BASE_IMAGE=alpine -t privacybydesign/irma:edge . +When you build for production, we recommend you to use the [latest release](https://github.com/privacybydesign/irmago/releases/latest). -When you build for production, we recommend you to build the [latest release](https://github.com/privacybydesign/irmago/releases/latest). You should replace `v0.0.0` with the latest version number. - - docker build -t privacybydesign/irma https://github.com/privacybydesign/irmago.git#v0.0.0 - -In case you want to build `v0.8.0` or lower, then you should do some extra steps. The `Dockerfile` was not part of the repository at that time. +In case you want to use `v0.12.6` or lower, then you should build it yourself. VERSION=v0.8.0 git checkout $VERSION git checkout master -- Dockerfile docker build -t privacybydesign/irma:$VERSION . -## Running the unit tests - -Some of the unit tests connect to locally running external services, namely PostgreSQL and an SMTP server running at port 1025. These need to be up and running before these tests can be executed. This can either be done using `docker-compose` or by following the instructions below to install the services manually. - -#### PostgreSQL +### Using pre-compiled binaries +You can find pre-compiled binaries of the `irma` command line tool on the [GitHub release page](https://github.com/privacybydesign/irmago/releases). +We recommend you to use the [latest release](https://github.com/privacybydesign/irmago/releases/latest). - * Install using e.g. `brew install postgresql`, or `apt-get install postgresql`, or via another package manager of your OS. - * Prepare the database and user: - - create database test; - create user testuser with encrypted password 'testpassword'; - grant all privileges on database test to testuser; - - This only needs to be done once. No table or rows need to be created; the unit tests do this themselves. - -#### SMTP server -For the SMTP server you can use [MailHog](https://github.com/mailhog/MailHog) (see also their [installation instructions](https://github.com/mailhog/MailHog#installation)): - * Install using `brew install mailhog` or `go get github.com/mailhog/MailHog`. - * Run using `MailHog`, or `~/go/bin/MailHog`, depending on your setup. +## Running the unit tests -For the unit tests it only matters that the SMTP server itself is running and accepts emails, but MailHog additionally comes with a webinterface showing incoming emails. By default this runs at . +Some of the unit tests connect to locally running external services, namely PostgreSQL, MySQL, Microsoft SQL Server and an SMTP server running at port 1025. These need to be up and running before these tests can be executed. This can be done using `docker-compose`. ### Running the tests @@ -82,16 +72,16 @@ In case you chose to start PostgreSQL and MailHog using `docker-compose`, you fi docker-compose up -When PostgreSQL and MailHog are running, the tests can be run using: +When the databases and MailHog are running, the tests can be run using: go test -p 1 ./... * The option `./...` makes sure all tests are run. You can also limit the number of tests by only running the tests from a single directory or even from a single file, for example only running all tests in the directory `./internal/sessiontest`. When you only want to execute one single test, for example the `TestDisclosureSession` test, you can do this by adding the option `-run TestDisclosureSession`. * The option `-p 1` is necessary to prevent parallel execution of tests. Most tests use file manipulation and therefore tests can interfere. -### Running without PostgreSQL, MailHog or Docker +### Running without Docker -If installing PostgreSQL, MailHog or Docker is not an option for you, then you can exclude all tests that use those by additionally passing `--tags=local_tests`: +If installing Docker or Docker alternatives is not an option for you, then you can exclude all tests that use those by additionally passing `--tags=local_tests`: go test -p 1 --tags=local_tests ./... diff --git a/attributes.go b/attributes.go index bed9c4ac..14465f4a 100644 --- a/attributes.go +++ b/attributes.go @@ -29,13 +29,13 @@ var ( credentialID = metadataField{16, 8} ) -// metadataField contains the length and offset of a field within a metadata attribute. +// MetadataField contains the length and offset of a field within a metadata attribute. type metadataField struct { length int offset int } -// metadataAttribute represents a metadata attribute. Contains the credential type, signing date, validity, and the public key counter. +// MetadataAttribute represents a metadata attribute. Contains the credential type, signing date, validity, and the public key counter. type MetadataAttribute struct { Int *big.Int pk *gabikeys.PublicKey @@ -59,16 +59,16 @@ type AttributeList struct { func NewAttributeListFromInts(ints []*big.Int, conf *Configuration) *AttributeList { metadata := MetadataFromInt(ints[0], conf) credtype := metadata.CredentialType() - idx := credtype.RevocationIndex + 1 - var rev bool + revocationSupported := false if credtype != nil { - rev = credtype.RevocationSupported() && + idx := credtype.RevocationIndex + 1 + revocationSupported = credtype.RevocationSupported() && len(ints) > idx && ints[idx] != nil && ints[idx].Cmp(bigZero) != 0 } return &AttributeList{ Ints: ints, MetadataAttribute: metadata, - RevocationSupported: rev, + RevocationSupported: revocationSupported, } } @@ -217,6 +217,26 @@ func (al *AttributeList) Attribute(identifier AttributeTypeIdentifier) Translate return nil } +func (al *AttributeList) CredentialInfo() *CredentialInfo { + credtype := al.CredentialType() + if credtype == nil { + return nil + } + id := credtype.Identifier() + issid := id.IssuerIdentifier() + return &CredentialInfo{ + ID: id.Name(), + IssuerID: issid.Name(), + SchemeManagerID: issid.SchemeManagerIdentifier().Name(), + SignedOn: Timestamp(al.SigningDate()), + Expires: Timestamp(al.Expiry()), + Attributes: al.Map(), + Hash: al.Hash(), + Revoked: al.Revoked, + RevocationSupported: al.RevocationSupported, + } +} + // MetadataFromInt wraps the given Int func MetadataFromInt(i *big.Int, conf *Configuration) *MetadataAttribute { return &MetadataAttribute{Int: i, Conf: conf} diff --git a/credinfo.go b/credinfo.go index c1668bba..baf85609 100644 --- a/credinfo.go +++ b/credinfo.go @@ -22,31 +22,11 @@ type CredentialInfo struct { // A CredentialInfoList is a list of credentials (implements sort.Interface). type CredentialInfoList []*CredentialInfo -func (attrs *AttributeList) CredentialInfo() *CredentialInfo { - credtype := attrs.CredentialType() - if credtype == nil { - return nil - } - id := credtype.Identifier() - issid := id.IssuerIdentifier() - return &CredentialInfo{ - ID: id.Name(), - IssuerID: issid.Name(), - SchemeManagerID: issid.SchemeManagerIdentifier().Name(), - SignedOn: Timestamp(attrs.SigningDate()), - Expires: Timestamp(attrs.Expiry()), - Attributes: attrs.Map(), - Hash: attrs.Hash(), - Revoked: attrs.Revoked, - RevocationSupported: attrs.RevocationSupported, - } -} - func (ci CredentialInfo) GetCredentialType(conf *Configuration) *CredentialType { return conf.CredentialTypes[ci.Identifier()] } -// Returns true if credential is expired at moment of calling this function +// IsExpired returns true if credential is expired at moment of calling this function func (ci CredentialInfo) IsExpired() bool { return ci.Expires.Before(Timestamp(time.Now())) } diff --git a/descriptions.go b/descriptions.go index 9d1740a0..f067f773 100644 --- a/descriptions.go +++ b/descriptions.go @@ -101,7 +101,7 @@ type AttributeType struct { Name TranslatedString Description TranslatedString - RandomBlind bool `xml:"randomblind,attr,optional" json:",omitempty"` + RandomBlind bool `xml:"randomblind,attr,omitempty" json:",omitempty"` Index int `xml:"-"` DisplayIndex *int `xml:"displayIndex,attr" json:",omitempty"` @@ -621,7 +621,7 @@ func (ad AttributeType) IsOptional() bool { return ad.Optional == "true" } -// Returns indices of random blind attributes within this credentialtype +// RandomBlindAttributeIndices returns indices of random blind attributes within this credentialtype // The indices coincide with indices of an AttributeList (metadataAttribute at index 0) func (ct *CredentialType) RandomBlindAttributeIndices() []int { indices := []int{} diff --git a/docker-compose.yml b/docker-compose.yml index 043e2700..21357e9e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ version: '3.1' services: # Dependencies for running unit tests and for running the 'irma' command line tool using one of the test configurations. postgres: - image: postgres:13 + image: postgres:15 environment: POSTGRES_USER: testuser POSTGRES_PASSWORD: testpassword @@ -16,7 +16,7 @@ services: ports: - 5432:5432 postgres-init: - image: postgres:13 + image: postgres:15 environment: PGHOST: postgres PGUSER: testuser @@ -32,6 +32,26 @@ services: # We have to wait until the database is up and running. # Database might already be running, so we need to do a cleanup first. command: /bin/sh -c "sleep 5 && psql -f cleanup.sql && psql -f schema.sql" + mysql: + image: mysql:8 + environment: + MYSQL_ROOT_PASSWORD: testpassword + MYSQL_DATABASE: test + MYSQL_USER: testuser + MYSQL_PASSWORD: testpassword + ports: + - 3306:3306 + sqlserver: + image: kcollins/mssql:2019-latest + environment: + ACCEPT_EULA: Y # Confirms your acceptance of the End-User Licensing Agreement. + SA_PASSWORD: test-Password # Include dash and uppercase letter to meet password requirements. + MSSQL_DATABASE: test + MSSQL_USER: testuser + MSSQL_PASSWORD: test-Password + MSSQL_PID: Developer + ports: + - 1433:1433 mailhog: image: mailhog/mailhog networks: @@ -67,6 +87,8 @@ services: - .:/irmago depends_on: - postgres + - mysql + - sqlserver - mailhog # The tests assume postgres and mailhog can be accessed on localhost. Therefore, we use host networking. network_mode: host diff --git a/go.mod b/go.mod index 2dc74bcf..c11ec132 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/go-co-op/gocron v1.28.3 github.com/go-errors/errors v1.4.2 github.com/go-redis/redis/v8 v8.11.5 - github.com/golang-jwt/jwt/v4 v4.4.1 + github.com/golang-jwt/jwt/v4 v4.5.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.1 github.com/mdp/qrterminal v1.0.1 @@ -31,6 +31,7 @@ require ( go.etcd.io/bbolt v1.3.6 gorm.io/driver/mysql v1.5.1 gorm.io/driver/postgres v1.5.2 + gorm.io/driver/sqlserver v1.5.1 gorm.io/gorm v1.25.1 ) @@ -47,6 +48,8 @@ require ( github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.2.1 // indirect @@ -62,6 +65,7 @@ require ( github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/microsoft/go-mssqldb v1.1.0 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect diff --git a/go.sum b/go.sum index 0619d6a9..0b4a1db9 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,10 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= @@ -78,6 +82,8 @@ 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= @@ -116,8 +122,13 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= -github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -174,9 +185,12 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -190,6 +204,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -205,6 +221,12 @@ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -224,6 +246,7 @@ 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/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -236,6 +259,8 @@ github.com/mdp/qrterminal v1.0.1 h1:07+fzVDlPuBlXS8tB0ktTAyf+Lp1j2+2zK3fBOL5b7c= github.com/mdp/qrterminal v1.0.1/go.mod h1:Z33WhxQe9B6CdW37HaVqcRKzP+kByF3q/qLxOGe12xQ= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/microsoft/go-mssqldb v1.1.0 h1:jsV+tpvcPTbNNKW0o3kiCD69kOHICsfjZ2VcVu2lKYc= +github.com/microsoft/go-mssqldb v1.1.0/go.mod h1:LzkFdl4z2Ck+Hi+ycGOTbL56VEfgoyA2DvYejrNGbRk= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= @@ -243,6 +268,8 @@ github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -269,6 +296,7 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw= github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= @@ -314,6 +342,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs= @@ -336,6 +365,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg= github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= @@ -355,9 +385,12 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -394,6 +427,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -429,7 +464,12 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/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-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -449,6 +489,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -492,17 +534,25 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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-20210616045830-e2b7044e8c71/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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220519141025-dcacdad47464/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/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/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -512,6 +562,10 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -566,6 +620,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -668,10 +724,14 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -682,6 +742,8 @@ gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= +gorm.io/driver/sqlserver v1.5.1 h1:wpyW/pR26U94uaujltiFGXY7fd2Jw5hC9PB1ZF/Y5s4= +gorm.io/driver/sqlserver v1.5.1/go.mod h1:AYHzzte2msKTmYBYsSIq8ZUsznLJwBdkB2wpI+kt0nM= gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/identifiers.go b/identifiers.go index deb20b99..617fb02b 100644 --- a/identifiers.go +++ b/identifiers.go @@ -129,8 +129,8 @@ func (oi metaObjectIdentifier) Root() string { } } -func (io metaObjectIdentifier) PartsCount() int { - return strings.Count(string(io), ".") +func (oi metaObjectIdentifier) PartsCount() int { + return strings.Count(string(oi), ".") } // NewRequestorSchemeIdentifier converts the specified identifier to a RequestorSchemeIdentifier. diff --git a/internal/keysharecore/operations_test.go b/internal/keysharecore/operations_test.go index 825dceff..04e50e02 100644 --- a/internal/keysharecore/operations_test.go +++ b/internal/keysharecore/operations_test.go @@ -183,7 +183,6 @@ func TestProofFunctionality(t *testing.T) { require.NoError(t, err) // For issuance, initially get P_t - // TODO: The result ps will be used in the generate commitment step and checked when the response is made. _, err = c.GeneratePs(secrets, jwtt, []irma.PublicKeyIdentifier{irma.PublicKeyIdentifier{Issuer: irma.NewIssuerIdentifier("test"), Counter: 1}}) require.NoError(t, err) diff --git a/internal/keysharecore/usersecrets.go b/internal/keysharecore/usersecrets.go index 72899d72..c555efd8 100644 --- a/internal/keysharecore/usersecrets.go +++ b/internal/keysharecore/usersecrets.go @@ -70,12 +70,12 @@ func (s *unencryptedUserSecrets) setID(id []byte) error { return nil } -func (user *unencryptedUserSecrets) verifyPin(pin string) error { +func (s *unencryptedUserSecrets) verifyPin(pin string) error { paddedPin, err := padBytes([]byte(pin), 64) if err != nil { return err } - if subtle.ConstantTimeCompare(user.Pin, paddedPin) != 1 { + if subtle.ConstantTimeCompare(s.Pin, paddedPin) != 1 { return ErrInvalidPin } return nil diff --git a/internal/sessiontest/legacy_test.go b/internal/sessiontest/legacy_test.go index 4358c88b..29f71eee 100644 --- a/internal/sessiontest/legacy_test.go +++ b/internal/sessiontest/legacy_test.go @@ -6,6 +6,7 @@ import ( irma "github.com/privacybydesign/irmago" "github.com/privacybydesign/irmago/internal/test" "github.com/privacybydesign/irmago/internal/testkeyshare" + "github.com/privacybydesign/irmago/server/irmaserver" "github.com/stretchr/testify/require" ) @@ -38,13 +39,16 @@ func testSessionUsingLegacyStorage(t *testing.T, dir string) { // Re-open client require.NoError(t, client.Close()) - client, handler = parseExistingStorage(t, handler.storage) + client, _ = parseExistingStorage(t, handler.storage) // Test whether credential is still there after the storage has been reloaded doSession(t, getDisclosureRequest(idRoot), client, nil, nil, nil, nil) } func TestWithoutPairingSupport(t *testing.T) { + irmaserver.AcceptInsecureProtocolVersions = true + defer func() { irmaserver.AcceptInsecureProtocolVersions = false }() + t.Run("SigningSession", apply(testSigningSession, nil, optionPrePairingClient)) t.Run("DisclosureSession", apply(testDisclosureSession, nil, optionPrePairingClient)) t.Run("NoAttributeDisclosureSession", apply(testNoAttributeDisclosureSession, nil, optionPrePairingClient)) diff --git a/internal/sessiontest/logs_test.go b/internal/sessiontest/logs_test.go index 066a440d..e0e82b97 100644 --- a/internal/sessiontest/logs_test.go +++ b/internal/sessiontest/logs_test.go @@ -84,7 +84,7 @@ func TestLogging(t *testing.T) { // Check whether log entry for signature session is actually stored require.NoError(t, client.Close()) - client, handler = parseExistingStorage(t, handler.storage) + client, _ = parseExistingStorage(t, handler.storage) logs, err = client.LoadNewestLogs(100) require.NoError(t, err) require.True(t, len(logs) == oldLogLength+3) diff --git a/internal/sessiontest/redis_test.go b/internal/sessiontest/redis_test.go index c27e9fdc..bc09544b 100644 --- a/internal/sessiontest/redis_test.go +++ b/internal/sessiontest/redis_test.go @@ -211,8 +211,9 @@ func TestRedisUpdates(t *testing.T) { var o interface{} transport := irma.NewHTTPTransport(qr.URL, false) - transport.SetHeader(irma.MinVersionHeader, "2.5") - transport.SetHeader(irma.MaxVersionHeader, "2.5") + transport.SetHeader(irma.MinVersionHeader, "2.8") + transport.SetHeader(irma.MaxVersionHeader, "2.8") + transport.SetHeader(irma.AuthorizationHeader, "testauthtoken") clientToken, err := mr.Get("token:" + string(token)) require.NoError(t, err) diff --git a/internal/sessiontest/revocation_test.go b/internal/sessiontest/revocation_test.go index d3909e91..905d5538 100644 --- a/internal/sessiontest/revocation_test.go +++ b/internal/sessiontest/revocation_test.go @@ -13,7 +13,9 @@ import ( "time" "github.com/go-co-op/gocron" + "gorm.io/driver/mysql" "gorm.io/driver/postgres" + "gorm.io/driver/sqlserver" "gorm.io/gorm" "github.com/privacybydesign/gabi" @@ -29,8 +31,11 @@ import ( ) var ( - revocationDbType, revocationDbStr = "postgres", "host=127.0.0.1 port=5432 user=testuser dbname=test password='testpassword' sslmode=disable" - //revocationDbType, revocationDbStr = "mysql", "testuser:testpassword@tcp(127.0.0.1)/test" + revocationDbStrs = map[string]string{ + "postgres": "host=127.0.0.1 port=5432 user=testuser dbname=test password='testpassword' sslmode=disable", + "mysql": "testuser:testpassword@tcp(127.0.0.1)/test", + "sqlserver": "sqlserver://testuser:test-Password@127.0.0.1:1433?database=test", + } revocationPkCounter uint = 2 ) @@ -93,9 +98,21 @@ func testRevocation(t *testing.T, attr irma.AttributeTypeIdentifier, client *irm require.False(t, satisfiable) } -func TestRevocationAll(t *testing.T) { +func TestRevocationPostgres(t *testing.T) { + testRevocationAll(t, "postgres") +} + +func TestRevocationMySQL(t *testing.T) { + testRevocationAll(t, "mysql") +} + +func TestRevocationSQLServer(t *testing.T) { + testRevocationAll(t, "sqlserver") +} + +func testRevocationAll(t *testing.T, dbType string) { t.Run("Revocation", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() client, handler := parseStorage(t) defer test.ClearTestStorage(t, client, handler.storage) @@ -103,7 +120,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("RevocationServerSessions", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() // issue a MijnOverheid.root instance with revocation enabled @@ -133,7 +150,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("MixRevocationNonRevocation", func(t *testing.T) { - revServer, client, handler := revocationSetup(t, nil) + revServer, client, handler := revocationSetup(t, nil, dbType) defer test.ClearTestStorage(t, client, handler.storage) defer revServer.Stop() @@ -154,7 +171,7 @@ func TestRevocationAll(t *testing.T) { irmaServer := StartIrmaServer(t, nil) defer irmaServer.Stop() - revServer, client, handler := revocationSetup(t, nil) + revServer, client, handler := revocationSetup(t, nil, dbType) defer test.ClearTestStorage(t, client, handler.storage) defer revServer.Stop() @@ -187,7 +204,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("POSTUpdates", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() irmaServer := StartIrmaServer(t, nil) defer irmaServer.Stop() @@ -227,7 +244,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("NoKnownAccumulator", func(t *testing.T) { - revServer, client, handler := revocationSetup(t, nil) + revServer, client, handler := revocationSetup(t, nil, dbType) defer test.ClearTestStorage(t, client, handler.storage) // stop revocation server so the verifier cannot fetch revocation state @@ -240,7 +257,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("OtherAccumulator", func(t *testing.T) { - revServer, client, handler := revocationSetup(t, nil) + revServer, client, handler := revocationSetup(t, nil, dbType) defer test.ClearTestStorage(t, client, handler.storage) defer revServer.Stop() @@ -322,7 +339,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("ClientSessionServerUpdate", func(t *testing.T) { - revServer, client, handler := revocationSetup(t, nil) + revServer, client, handler := revocationSetup(t, nil, dbType) defer test.ClearTestStorage(t, client, handler.storage) defer revServer.Stop() @@ -340,7 +357,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("UpdateSameIndex", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() irmaServer := StartIrmaServer(t, nil) defer irmaServer.Stop() @@ -375,7 +392,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("ClientAutoServerUpdate", func(t *testing.T) { - revServer, client, handler := revocationSetup(t, nil) // revocation server is stopped manually below + revServer, client, handler := revocationSetup(t, nil, dbType) // revocation server is stopped manually below defer test.ClearTestStorage(t, client, handler.storage) // Advance the accumulator by performing 3 revocations @@ -420,7 +437,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("LaggingNonRevocationWitness", func(t *testing.T) { - revServer, client, handler := revocationSetup(t, nil) + revServer, client, handler := revocationSetup(t, nil, dbType) defer revServer.Stop() defer test.ClearTestStorage(t, client, handler.storage) @@ -475,7 +492,7 @@ func TestRevocationAll(t *testing.T) { defer irmaServer.Stop() // issue a credential, populating irmaServer's revocation memdb - revServer, client, handler := revocationSetup(t, irmaServer) + revServer, client, handler := revocationSetup(t, irmaServer, dbType) defer test.ClearTestStorage(t, client, handler.storage) defer revServer.Stop() @@ -489,7 +506,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("RestartRevocationServer", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) rev := revServer.conf.IrmaConfiguration.Revocation sacc1, err := rev.Accumulator(revocationTestCred, revocationPkCounter) require.NoError(t, err) @@ -506,7 +523,7 @@ func TestRevocationAll(t *testing.T) { revServer.Stop() - revServer = startRevocationServer(t, false) + revServer = startRevocationServer(t, false, dbType) defer revServer.Stop() rev = revServer.conf.IrmaConfiguration.Revocation sacc3, err := rev.Accumulator(revocationTestCred, revocationPkCounter) @@ -524,7 +541,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("DeleteExpiredIssuanceRecords", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() // Insert expired issuance record @@ -551,7 +568,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("RevokeMany", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() rev := revServer.conf.IrmaConfiguration.Revocation sacc, err := rev.Accumulator(revocationTestCred, revocationPkCounter) @@ -596,7 +613,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("RevocationTolerance", func(t *testing.T) { - revServer, client, handler := revocationSetup(t, nil) + revServer, client, handler := revocationSetup(t, nil, dbType) defer test.ClearTestStorage(t, client, handler.storage) defer revServer.Stop() start := time.Now() @@ -627,7 +644,7 @@ func TestRevocationAll(t *testing.T) { }) t.Run("Cache", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() rev := revServer.conf.IrmaConfiguration.Revocation sacc, err := rev.Accumulator(revocationTestCred, revocationPkCounter) @@ -692,7 +709,7 @@ func TestRevocationAll(t *testing.T) { // Restore revocation setup credtyp.RevocationServers = servers credtyp.AttributeTypes = append(credtyp.AttributeTypes, revAttr) - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() // Try disclosure session requiring nonrevocation proof @@ -703,8 +720,9 @@ func TestRevocationAll(t *testing.T) { } func TestKeyshareRevocation(t *testing.T) { + dbType := "postgres" t.Run("Keyshare", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() keyshareServer := testkeyshare.StartKeyshareServer(t, logger, irma.NewSchemeManagerIdentifier("test")) defer keyshareServer.Stop() @@ -715,7 +733,7 @@ func TestKeyshareRevocation(t *testing.T) { }) t.Run("Both", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() keyshareServer := testkeyshare.StartKeyshareServer(t, logger, irma.NewSchemeManagerIdentifier("test")) defer keyshareServer.Stop() @@ -727,7 +745,7 @@ func TestKeyshareRevocation(t *testing.T) { }) t.Run("KeyshareMultipleCredentials", func(t *testing.T) { - revServer := startRevocationServer(t, true) + revServer := startRevocationServer(t, true, dbType) defer revServer.Stop() keyshareServer := testkeyshare.StartKeyshareServer(t, logger, irma.NewSchemeManagerIdentifier("test")) defer keyshareServer.Stop() @@ -793,8 +811,8 @@ func revocationSession(t *testing.T, client *irmaclient.Client, request irma.Ses } // revocationSetup sets up an irmaclient with a revocation-enabled credential, constants, and revocation key material. -func revocationSetup(t *testing.T, irmaServer *IrmaServer) (*IrmaServer, *irmaclient.Client, *TestClientHandler) { - revServer := startRevocationServer(t, true) +func revocationSetup(t *testing.T, irmaServer *IrmaServer, dbType string) (*IrmaServer, *irmaclient.Client, *TestClientHandler) { + revServer := startRevocationServer(t, true, dbType) // issue a MijnOverheid.root instance with revocation enabled client, handler := parseStorage(t) @@ -850,7 +868,7 @@ func fakeMultipleRevocations(t *testing.T, count uint64, conf *irma.RevocationSt require.NoError(t, conf.AddUpdate(revocationTestCred, update)) } -func revocationConf(_ *testing.T) *server.Configuration { +func revocationConf(_ *testing.T, dbType string) *server.Configuration { return &server.Configuration{ URL: revocationServerURL, Logger: logger, @@ -863,17 +881,25 @@ func revocationConf(_ *testing.T) *server.Configuration { revKeyshareTestCred: {Authority: true}, revKeyshareSecondTestCred: {Authority: true}, }, - RevocationDBConnStr: revocationDbStr, - RevocationDBType: revocationDbType, + RevocationDBConnStr: revocationDbStrs[dbType], + RevocationDBType: dbType, } } -func startRevocationServer(t *testing.T, droptables bool) *IrmaServer { +func startRevocationServer(t *testing.T, droptables bool, dbType string) *IrmaServer { var err error // Connect to database and clear records from previous test runs if droptables { - g, err := gorm.Open(postgres.Open(revocationDbStr)) + var g *gorm.DB + switch dbType { + case "postgres": + g, err = gorm.Open(postgres.Open(revocationDbStrs[dbType])) + case "mysql": + g, err = gorm.Open(mysql.Open(revocationDbStrs[dbType])) + case "sqlserver": + g, err = gorm.Open(sqlserver.Open(revocationDbStrs[dbType])) + } require.NoError(t, err) require.NoError(t, g.Migrator().DropTable((*irma.EventRecord)(nil))) require.NoError(t, g.Migrator().DropTable((*irma.AccumulatorRecord)(nil))) @@ -887,7 +913,7 @@ func startRevocationServer(t *testing.T, droptables bool) *IrmaServer { } // Start revocation server - conf := revocationConf(t) + conf := revocationConf(t, dbType) revocationServer, err := irmaserver.New(conf) require.NoError(t, err) mux := http.NewServeMux() diff --git a/internal/sessiontest/session_test.go b/internal/sessiontest/session_test.go index affd3aee..d4b020a9 100644 --- a/internal/sessiontest/session_test.go +++ b/internal/sessiontest/session_test.go @@ -166,7 +166,7 @@ func testIssuanceSameAttributesNotSingleton(t *testing.T, conf interface{}, opts // Also check whether this is actually stored require.NoError(t, client.Close()) - client, handler = parseExistingStorage(t, handler.storage) + client, _ = parseExistingStorage(t, handler.storage) require.Equal(t, prevLen+1, len(client.CredentialInfoList())) } @@ -272,7 +272,7 @@ func testIssuanceSingletonCredential(t *testing.T, conf interface{}, opts ...opt // Also check whether this is actually stored require.NoError(t, client.Close()) - client, handler = parseExistingStorage(t, handler.storage) + client, _ = parseExistingStorage(t, handler.storage) require.NotNil(t, client.Attributes(credid, 0)) require.Nil(t, client.Attributes(credid, 1)) } @@ -447,7 +447,7 @@ func testIssuedCredentialIsStored(t *testing.T, conf interface{}, opts ...option doSession(t, issuanceRequest, client, nil, nil, nil, conf, opts...) require.NoError(t, client.Close()) - client, handler = parseExistingStorage(t, handler.storage) + client, _ = parseExistingStorage(t, handler.storage) id := irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.fullName.familyname") doSession(t, getDisclosureRequest(id), client, nil, nil, nil, conf, opts...) } @@ -962,7 +962,7 @@ func TestPOSTSizeLimit(t *testing.T) { req, err := http.NewRequest( http.MethodPost, requestorServerURL+"/session/", - bytes.NewReader(make([]byte, server.PostSizeLimit+1, server.PostSizeLimit+1)), + bytes.NewReader(make([]byte, server.PostSizeLimit+1)), ) require.NoError(t, err) req.Header.Set("Content-Type", "application/json; charset=UTF-8") @@ -1091,12 +1091,36 @@ func TestDoubleGET(t *testing.T) { // Simulate the first GET by the client in the session protocol, twice var o interface{} transport := irma.NewHTTPTransport(qr.URL, false) - transport.SetHeader(irma.MinVersionHeader, "2.5") - transport.SetHeader(irma.MaxVersionHeader, "2.5") + transport.SetHeader(irma.MinVersionHeader, "2.8") + transport.SetHeader(irma.MaxVersionHeader, "2.8") + transport.SetHeader(irma.AuthorizationHeader, "testauthtoken") require.NoError(t, transport.Get("", &o)) require.NoError(t, transport.Get("", &o)) } +func TestInsecureProtocolVersion(t *testing.T) { + irmaServer := StartIrmaServer(t, nil) + defer irmaServer.Stop() + + // Test whether the server accepts a request with an insecure protocol version + request := irma.NewDisclosureRequest(irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")) + + qr, _, _, err := irmaServer.irma.StartSession(request, func(result *server.SessionResult) {}) + require.NoError(t, err) + + var o interface{} + transport := irma.NewHTTPTransport(qr.URL, false) + transport.SetHeader(irma.MinVersionHeader, "2.7") + transport.SetHeader(irma.MaxVersionHeader, "2.7") + transport.SetHeader(irma.AuthorizationHeader, "testauthtoken") + err = transport.Get("", &o) + require.Error(t, err) + serr, ok := err.(*irma.SessionError) + require.True(t, ok) + require.Equal(t, server.ErrorProtocolVersion.Status, serr.RemoteStatus) + require.Equal(t, string(server.ErrorProtocolVersion.Type), serr.RemoteError.ErrorName) +} + func TestClientDeveloperMode(t *testing.T) { common.ForceHTTPS = true defer func() { common.ForceHTTPS = false }() diff --git a/irma/cmd/genkeypair.go b/irma/cmd/genkeypair.go index c2132834..125bd28c 100644 --- a/irma/cmd/genkeypair.go +++ b/irma/cmd/genkeypair.go @@ -116,7 +116,7 @@ var genkeypairCmd = &cobra.Command{ // Now generate the key pair sysParams, ok := gabikeys.DefaultSystemParameters[keylength] if !ok { - return fmt.Errorf("Unsupported key length, should be one of %v", gabikeys.DefaultKeyLengths) + return fmt.Errorf("unsupported key length, should be one of %v", gabikeys.DefaultKeyLengths) } privk, pubk, err := gabikeys.GenerateKeyPair(sysParams, numAttributes, counter, expiryDate) if err != nil { diff --git a/irma/cmd/issuer-keyprove.go b/irma/cmd/issuer-keyprove.go index 4cc01dfa..2717b227 100644 --- a/irma/cmd/issuer-keyprove.go +++ b/irma/cmd/issuer-keyprove.go @@ -119,7 +119,7 @@ may be used.`, }() // Build the proof - bases := append([]*big.Int{pk.Z, pk.S}) + bases := []*big.Int{pk.Z, pk.S} if pk.G != nil { bases = append(bases, pk.G) } diff --git a/irma/cmd/issuer-keyverify.go b/irma/cmd/issuer-keyverify.go index cd13ad77..04ed7085 100644 --- a/irma/cmd/issuer-keyverify.go +++ b/irma/cmd/issuer-keyverify.go @@ -102,7 +102,7 @@ On machines of 2 - 3 GHz verification will take some 5 - 15 minutes, during whic follower.StepDone() // Construct proof structure - bases := append([]*big.Int{pk.Z, pk.S}) + bases := []*big.Int{pk.Z, pk.S} if pk.G != nil { bases = append(bases, pk.G) } diff --git a/irma/cmd/request.go b/irma/cmd/request.go index 65845368..6e485b70 100644 --- a/irma/cmd/request.go +++ b/irma/cmd/request.go @@ -310,7 +310,6 @@ func authmethodAlias(f *pflag.FlagSet, name string) pflag.NormalizedName { switch name { case "authmethod": name = "auth-method" - break } return pflag.NormalizedName(name) } diff --git a/irma/cmd/sign.go b/irma/cmd/sign.go index 156b29b6..6ff58052 100644 --- a/irma/cmd/sign.go +++ b/irma/cmd/sign.go @@ -184,7 +184,7 @@ func skipSigning(path string, info os.FileInfo, typ irma.SchemeType) bool { } if !strings.HasSuffix(path, ".xml") && !strings.HasSuffix(path, ".png") && - !regexp.MustCompile("kss-\\d+\\.pem$").Match([]byte(filepath.Base(path))) && + !regexp.MustCompile(`kss-\d+\.pem$`).Match([]byte(filepath.Base(path))) && filepath.Base(path) != "timestamp" { return true } diff --git a/irmaclient/client.go b/irmaclient/client.go index 9b46a22d..cdb052b4 100644 --- a/irmaclient/client.go +++ b/irmaclient/client.go @@ -15,7 +15,6 @@ import ( irma "github.com/privacybydesign/irmago" "github.com/privacybydesign/irmago/internal/common" "github.com/privacybydesign/irmago/internal/concmap" - "github.com/sirupsen/logrus" ) // This file contains most methods of the Client (c.f. session.go @@ -74,6 +73,7 @@ type Client struct { credMutex sync.Mutex } +// Preferences contains the preferences of the user of this client. // TODO: consider if we should save irmamobile preferences here, because they would automatically // be part of any backup and syncing solution we implement at a later time type Preferences struct { @@ -251,15 +251,6 @@ func (client *Client) loadCredentialStorage() (err error) { return } -func (client *Client) nonrevCredPrepareCache(credid irma.CredentialTypeIdentifier, index int) error { - irma.Logger.WithFields(logrus.Fields{"credid": credid, "index": index}).Debug("Preparing cache") - cred, err := client.credential(credid, index) - if err != nil { - return err - } - return cred.NonrevPrepareCache() -} - func (client *Client) reportError(err error) { irma.Logger.Error(err) client.handler.ReportError(err) @@ -451,8 +442,8 @@ func (client *Client) RemoveCredentialByHash(hash string) error { return client.RemoveCredential(cred.CredentialType().Identifier(), index) } -// Removes all attributes, signatures, logs and userdata -// Includes the user's secret key, keyshare servers and preferences/updates +// RemoveStorage removes all attributes, signatures, logs and userdata. +// This includes the user's secret key, keyshare servers and preferences/updates. // A fresh secret key is installed. func (client *Client) RemoveStorage() error { var err error @@ -1462,7 +1453,7 @@ func (client *Client) ConfigurationUpdated(downloaded *irma.IrmaIdentifierSet) e if diff <= 0 { continue } - attrs = append(attrs, make([]*big.Int, diff, diff)...) + attrs = append(attrs, make([]*big.Int, diff)...) for j := len(attrs) - diff; j < len(attrs); j++ { attrs[j] = big.NewInt(0) } diff --git a/irmaclient/irmaclient_test.go b/irmaclient/irmaclient_test.go index f9492230..0ddc509a 100644 --- a/irmaclient/irmaclient_test.go +++ b/irmaclient/irmaclient_test.go @@ -292,7 +292,7 @@ func TestCredentialRemoval(t *testing.T) { // Also check whether credential is removed after reloading the storage err = client.storage.db.Close() require.NoError(t, err) - client, handler = parseExistingStorage(t, handler.storage) + client, _ = parseExistingStorage(t, handler.storage) cred, err = client.credential(id2, 0) require.NoError(t, err) require.Nil(t, cred) @@ -359,7 +359,7 @@ func TestKeyshareEnrollmentRemoval(t *testing.T) { err = client.storage.db.Close() require.NoError(t, err) - client, handler = parseExistingStorage(t, handler.storage) + client, _ = parseExistingStorage(t, handler.storage) require.NotContains(t, client.keyshareServers, "test") } diff --git a/irmaclient/keyshare.go b/irmaclient/keyshare.go index fc17cf97..4906706c 100644 --- a/irmaclient/keyshare.go +++ b/irmaclient/keyshare.go @@ -190,30 +190,6 @@ func (kss *keyshareServer) tokenValid(conf *irma.Configuration) bool { return true } -func (ks *keyshareSession) fail(manager irma.SchemeManagerIdentifier, err error) { - serr, ok := err.(*irma.SessionError) - if ok { - if serr.RemoteError != nil && len(serr.RemoteError.ErrorName) > 0 { - switch serr.RemoteError.ErrorName { - case "USER_NOT_FOUND": - ks.sessionHandler.KeyshareEnrollmentDeleted(manager) - case "USER_NOT_REGISTERED": - ks.sessionHandler.KeyshareEnrollmentIncomplete(manager) - case "USER_BLOCKED": - duration, err := strconv.Atoi(serr.RemoteError.Message) - if err != nil { // Not really clear what to do with duration, but should never happen anyway - duration = -1 - } - ks.sessionHandler.KeyshareBlocked(manager, duration) - default: - ks.sessionHandler.KeyshareError(&manager, err) - } - } - } else { - ks.sessionHandler.KeyshareError(&manager, err) - } -} - // VerifyPin asks for a pin, repeatedly if necessary, informing the handler of success or failure. // It returns whether the authentication was successful or not. func (ks *keyshareSession) VerifyPin(attempts int) bool { diff --git a/irmaclient/revocation.go b/irmaclient/revocation.go index 99c0bd95..a97ffdb7 100644 --- a/irmaclient/revocation.go +++ b/irmaclient/revocation.go @@ -68,7 +68,7 @@ func (client *Client) initRevocation() { irma.Logger.WithFields(logrus.Fields{ "random": r, "prob": p, - "lastupdated": time.Now().Sub(cred.NonRevocationWitness.Updated).Seconds(), + "lastupdated": time.Since(cred.NonRevocationWitness.Updated).Seconds(), "credtype": id, "hash": attrs.Hash(), }).Debug("scheduling nonrevocation witness remote update") @@ -300,7 +300,7 @@ func probability(lastUpdate time.Time, refindex uint64) float64 { refprobability = 0.75 * asymptote // probability after one week ) f := math.Tan(math.Pi * refprobability / (2 * asymptote)) - i := time.Now().Sub(lastUpdate).Seconds() + i := time.Since(lastUpdate).Seconds() return 2 * asymptote / math.Pi * math.Atan(i/float64(refindex)*f) } diff --git a/irmaclient/session.go b/irmaclient/session.go index 299c9d44..50fff41e 100644 --- a/irmaclient/session.go +++ b/irmaclient/session.go @@ -370,8 +370,8 @@ func (session *session) processSessionInfo() { issuedAt := time.Now() _, err := ir.GetCredentialInfoList(session.client.Configuration, session.Version, issuedAt) if err != nil { - if err, ok := err.(*irma.SessionError); ok { - session.fail(err) + if serr, ok := err.(*irma.SessionError); ok { + session.fail(serr) } else { session.fail(&irma.SessionError{ErrorType: irma.ErrorUnknownIdentifier, Err: err}) } diff --git a/irmaclient/signer.go b/irmaclient/signer.go index 926358d7..581c069c 100644 --- a/irmaclient/signer.go +++ b/irmaclient/signer.go @@ -21,7 +21,7 @@ type Signer interface { // encoding used for JWTs (in which the bytes of r and s are concatenated after each other in one // byte slice). func signatureJwtEncoding(signature []byte) ([]byte, error) { - ints := make([]*gobig.Int, 2, 2) + ints := make([]*gobig.Int, 2) _, err := asn1.Unmarshal(signature, &ints) if err != nil { return nil, err diff --git a/irmaconfig.go b/irmaconfig.go index 7ff840ea..a78e4f0d 100644 --- a/irmaconfig.go +++ b/irmaconfig.go @@ -67,7 +67,7 @@ type Configuration struct { readOnly bool } -// ConfigurationListeners are the interface provided to react to changes in schemes. +// ConfigurationListener are the interface provided to react to changes in schemes. type ConfigurationListener func(conf *Configuration) type UnknownIdentifierError struct { @@ -596,8 +596,6 @@ func (conf *Configuration) checkCredentialTypes(session SessionRequest, missing } return nil }) - - return } func (conf *Configuration) checkIdentifiers(session SessionRequest) (*IrmaIdentifierSet, *IrmaIdentifierSet, error) { diff --git a/irmago_test.go b/irmago_test.go index 06ef13f9..c8a12086 100644 --- a/irmago_test.go +++ b/irmago_test.go @@ -874,14 +874,6 @@ func credidptr(s string) *CredentialTypeIdentifier { id := credid(s) return &id } -func credinfo(id string) *CredentialInfo { - i := credid(id) - return &CredentialInfo{ - SchemeManagerID: i.Root(), - IssuerID: i.IssuerIdentifier().Name(), - ID: i.Name(), - } -} func credtype(id string, deps ...string) *CredentialType { i := credid(id) d := CredentialDependencies{{{}}} diff --git a/keyring.go b/keyring.go index 9e996725..d563b283 100644 --- a/keyring.go +++ b/keyring.go @@ -81,7 +81,7 @@ func NewPrivateKeyRingFolder(path string, conf *Configuration) (*PrivateKeyRingF return ring, nil } -func (_ *PrivateKeyRingFolder) parseFilename(filename string) (*IssuerIdentifier, *uint, error) { +func (*PrivateKeyRingFolder) parseFilename(filename string) (*IssuerIdentifier, *uint, error) { // This regexp returns one of the following: // [ "foo.bar.xml", "foo.bar", "", "" ] in case of "foo.bar.xml" // [ "foo.bar.xml", "foo.bar", ".2", "2" ] in case of "foo.bar.2.xml" diff --git a/messages.go b/messages.go index 73982c60..dee57e4f 100644 --- a/messages.go +++ b/messages.go @@ -65,7 +65,7 @@ func (v *ProtocolVersion) MarshalJSON() ([]byte, error) { return json.Marshal(v.String()) } -// Returns true if v is below the given version. +// Below returns true if v is below the given version. func (v *ProtocolVersion) Below(major, minor int) bool { if v.Major < major { return true @@ -73,10 +73,12 @@ func (v *ProtocolVersion) Below(major, minor int) bool { return v.Major == major && v.Minor < minor } +// BelowVersion returns true if v is below the given version. func (v *ProtocolVersion) BelowVersion(other *ProtocolVersion) bool { return v.Below(other.Major, other.Minor) } +// Above returns true if v is above the given version. func (v *ProtocolVersion) Above(major, minor int) bool { if v.Major > major { return true @@ -84,6 +86,7 @@ func (v *ProtocolVersion) Above(major, minor int) bool { return v.Major == major && v.Minor > minor } +// AboveVersion returns true if v is above the given version. func (v *ProtocolVersion) AboveVersion(other *ProtocolVersion) bool { return v.Above(other.Major, other.Minor) } @@ -172,8 +175,10 @@ type Qr struct { Type Action `json:"irmaqr"` } -// Tokens to identify a session from the perspective of the different agents +// RequestorToken identifies a session from the perspective of the requestor. type RequestorToken string + +// ClientToken identifies a session from the perspective of the client. type ClientToken string // ParseClientToken parses a string to a ClientToken after validating the input. @@ -195,8 +200,10 @@ func ParseRequestorToken(input string) (RequestorToken, error) { } // Authorization headers -type ClientAuthorization string -type FrontendAuthorization string +type ( + ClientAuthorization string + FrontendAuthorization string +) // Client statuses const ( @@ -393,12 +400,12 @@ func (ppcm *ProofPCommitmentMap) MarshalJSON() ([]byte, error) { } type PMap struct { - Ps map[PublicKeyIdentifier]*big.Int `json:"p"` + Ps map[PublicKeyIdentifier]*big.Int `json:"ps"` } func (pm *PMap) MarshalJSON() ([]byte, error) { var encPM struct { - Ps map[string]*big.Int `json:"p"` + Ps map[string]*big.Int `json:"ps"` } encPM.Ps = make(map[string]*big.Int) diff --git a/requests.go b/requests.go index 00b67db5..814218d9 100644 --- a/requests.go +++ b/requests.go @@ -695,7 +695,7 @@ func stringSliceEqual(a, b []string) bool { if len(a) != len(b) { return false } - for i, _ := range a { + for i := range a { if a[i] != b[i] { return false } @@ -768,7 +768,7 @@ func (ir *IssuanceRequest) Identifiers() *IrmaIdentifierSet { ir.ids.Issuers[issuer] = struct{}{} credID := credreq.CredentialTypeID ir.ids.CredentialTypes[credID] = struct{}{} - for attr, _ := range credreq.Attributes { // this is kind of ugly + for attr := range credreq.Attributes { // this is kind of ugly ir.ids.AttributeTypes[NewAttributeTypeIdentifier(credID.String()+"."+attr)] = struct{}{} } if ir.ids.PublicKeys[issuer] == nil { @@ -879,20 +879,22 @@ func (sr *SignatureRequest) Validate() error { return nil } -// Check if Timestamp is before other Timestamp. Used for checking expiry of attributes +// Before checks if Timestamp is before other Timestamp. Used for checking expiry of attributes. func (t Timestamp) Before(u Timestamp) bool { return time.Time(t).Before(time.Time(u)) } +// After checks if Timestamp is after other Timestamp. Used for checking expiry of attributes. func (t Timestamp) After(u Timestamp) bool { return time.Time(t).After(time.Time(u)) } +// Sub returns the time difference between two Timestamps. func (t Timestamp) Sub(u Timestamp) time.Duration { return time.Time(t).Sub(time.Time(u)) } -// To check whether Timestamp is uninitialized +// IsZero checks whether Timestamp is uninitialized func (t Timestamp) IsZero() bool { return time.Time(t).IsZero() } @@ -925,7 +927,7 @@ func (t *Timestamp) UnmarshalJSON(b []byte) error { return nil } -// Timestamp implements Stringer. +// String returns the timestamp as a Unix time string. func (t *Timestamp) String() string { return fmt.Sprint(time.Time(*t).Unix()) } diff --git a/revocation.go b/revocation.go index 4b24dff0..9f32cd36 100644 --- a/revocation.go +++ b/revocation.go @@ -720,7 +720,7 @@ func (rs *RevocationStorage) SetRevocationUpdates(b *BaseRequest) error { Logger.WithError(err).Warnf( "failed to fetch revocation updates for %s, nonrevocation is guaranteed only until %s ago", credid, - time.Now().Sub(updated).String(), + time.Since(updated).String(), ) } else { Logger.WithError(err).Errorf("revocation is disabled for %s: failed to fetch revocation updates and none are known locally", credid) diff --git a/revocation_db.go b/revocation_db.go index 0df4ab46..20dd601a 100644 --- a/revocation_db.go +++ b/revocation_db.go @@ -14,6 +14,7 @@ import ( "github.com/privacybydesign/gabi/signed" "gorm.io/driver/mysql" "gorm.io/driver/postgres" + "gorm.io/driver/sqlserver" "gorm.io/gorm" "gorm.io/gorm/clause" "gorm.io/gorm/logger" @@ -130,6 +131,8 @@ func newSQLStorage(debug bool, dbtype, connstr string) (sqlRevStorage, error) { dialector = postgres.Open(connstr) case "mysql": dialector = mysql.Open(connstr) + case "sqlserver": + dialector = sqlserver.Open(connstr) default: return sqlRevStorage{}, errors.New("unsupported database type") } @@ -271,8 +274,16 @@ func (s sqlRevStorage) AppendAccumulatorUpdate( return s.gorm.Transaction(func(tx *gorm.DB) error { // Retrieve the current accumulator state for every public key of the credential and lock the rows for update. var accs []*AccumulatorRecord - if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&accs, map[string]interface{}{"cred_type": id}).Error; err != nil { - return err + + // Microsoft SQL server does not support the locking clause, so we have to use a raw query instead. + if s.gorm.Dialector.Name() == "sqlserver" { + if err := tx.Raw("SELECT * FROM accumulator_records WITH (UPDLOCK, ROWLOCK) WHERE cred_type = ?", id).Scan(&accs).Error; err != nil { + return err + } + } else { + if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&accs, map[string]interface{}{"cred_type": id}).Error; err != nil { + return err + } } // Accumulators always relate to the latest revocation event of its type. We retrieve those too and combine them in revocationUpdateHead instances. @@ -624,6 +635,8 @@ func (eventHash) GormDBDataType(db *gorm.DB, _ *schema.Field) string { return "bytea" case "mysql": return "blob" + case "sqlserver": + return "varbinary(max)" default: return "" } @@ -636,6 +649,8 @@ func (signedMessage) GormDBDataType(db *gorm.DB, _ *schema.Field) string { return "bytea" case "mysql": return "blob" + case "sqlserver": + return "varbinary(max)" default: return "" } @@ -677,6 +692,8 @@ func (RevocationAttribute) GormDBDataType(db *gorm.DB, _ *schema.Field) string { return "bytea" case "mysql": return "blob" + case "sqlserver": + return "varbinary(max)" default: return "" } diff --git a/schemes.go b/schemes.go index 80ed56d9..d226e28a 100644 --- a/schemes.go +++ b/schemes.go @@ -62,7 +62,7 @@ type ( path() string setPath(path string) parseContents(conf *Configuration) error - validate(conf *Configuration) (error, SchemeManagerStatus) + validate(conf *Configuration) (SchemeManagerStatus, error) update() error handleUpdateFile(conf *Configuration, path, filename string, bts []byte, transport *HTTPTransport, _ *IrmaIdentifierSet) error delete(conf *Configuration) error @@ -298,7 +298,7 @@ func (conf *Configuration) ParseSchemeFolder(dir string) (scheme Scheme, serr er }() // validate scheme contents - if err, status := scheme.validate(conf); err != nil { + if status, err := scheme.validate(conf); err != nil { serr = &SchemeManagerError{Scheme: id, Status: status, Err: err} return } @@ -362,7 +362,7 @@ func (conf *Configuration) parseSchemeDescription(dir string) (Scheme, SchemeMan return nil, SchemeManagerStatusParsingError, err } - index, err, _ := conf.parseIndex(dir) + index, _, err := conf.parseIndex(dir) if err != nil { return nil, SchemeManagerStatusParsingError, err } @@ -730,26 +730,26 @@ func (conf *Configuration) readHashedFile(path string, hash SchemeFileHash) ([]b } // parseIndex parses the index file of the specified manager. -func (conf *Configuration) parseIndex(dir string) (SchemeManagerIndex, error, SchemeManagerStatus) { +func (conf *Configuration) parseIndex(dir string) (SchemeManagerIndex, SchemeManagerStatus, error) { if err := conf.verifySignature(dir); err != nil { - return nil, err, SchemeManagerStatusInvalidSignature + return nil, SchemeManagerStatusInvalidSignature, err } path := filepath.Join(dir, "index") if err := common.AssertPathExists(path); err != nil { - return nil, fmt.Errorf("missing scheme manager index file; tried %s", path), SchemeManagerStatusInvalidIndex + return nil, SchemeManagerStatusInvalidIndex, fmt.Errorf("missing scheme manager index file; tried %s", path) } indexbts, err := os.ReadFile(path) if err != nil { - return nil, err, SchemeManagerStatusInvalidIndex + return nil, SchemeManagerStatusInvalidIndex, err } index := SchemeManagerIndex(make(map[string]SchemeFileHash)) if err = index.FromString(string(indexbts)); err != nil { - return nil, err, SchemeManagerStatusInvalidIndex + return nil, SchemeManagerStatusInvalidIndex, err } if err = conf.checkUnsignedFiles(dir, index); err != nil { - return nil, err, SchemeManagerStatusContentParsingError + return nil, SchemeManagerStatusContentParsingError, err } - return index, nil, SchemeManagerStatusValid + return index, SchemeManagerStatusValid, nil } func (conf *Configuration) checkUnsignedFiles(dir string, index SchemeManagerIndex) error { @@ -903,9 +903,9 @@ var ( regexp.MustCompile(`\.DS_Store$`), } - issPattern = regexp.MustCompile("^([^/]+)/description\\.xml") - credPattern = regexp.MustCompile("([^/]+)/Issues/([^/]+)/description\\.xml") - keyPattern = regexp.MustCompile("([^/]+)/PublicKeys/(\\d+)\\.xml") + issPattern = regexp.MustCompile(`^([^/]+)/description\.xml`) + credPattern = regexp.MustCompile(`([^/]+)/Issues/([^/]+)/description\.xml`) + keyPattern = regexp.MustCompile(`([^/]+)/PublicKeys/(\d+)\.xml`) ) func newScheme(typ SchemeType) Scheme { @@ -1038,15 +1038,6 @@ func (ct CredentialType) validateDependencies(conf *Configuration, validatedDeps return nil } -func (d DependencyChain) contains(item CredentialTypeIdentifier) bool { - for _, dep := range d { - if dep == item { - return true - } - } - return false -} - func (d DependencyChain) String() string { deps := make([]string, len(d)) for i := 0; i < len(d); i++ { @@ -1055,23 +1046,23 @@ func (d DependencyChain) String() string { return strings.Join(deps, ", ") } -func (scheme *SchemeManager) validate(conf *Configuration) (error, SchemeManagerStatus) { +func (scheme *SchemeManager) validate(conf *Configuration) (SchemeManagerStatus, error) { if scheme.XMLVersion < 7 { - return errors.New("Unsupported scheme manager description"), SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, errors.New("Unsupported scheme manager description") } if scheme.KeyshareServer != "" { if err := common.AssertPathExists(filepath.Join(scheme.path(), "kss-0.pem")); err != nil { - return errors.Errorf("Scheme %s has keyshare URL but no keyshare public key kss-0.pem", scheme.ID), SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, errors.Errorf("Scheme %s has keyshare URL but no keyshare public key kss-0.pem", scheme.ID) } } conf.validateTranslations(fmt.Sprintf("Scheme %s", scheme.ID), scheme, scheme.Languages) // Verify that all other files are validly signed if err := scheme.verifyFiles(conf); err != nil { - return err, SchemeManagerStatusInvalidSignature + return SchemeManagerStatusInvalidSignature, err } - return nil, SchemeManagerStatusValid + return SchemeManagerStatusValid, nil } func (scheme *SchemeManager) update() error { @@ -1164,7 +1155,7 @@ func (scheme *SchemeManager) present(id string, conf *Configuration) bool { return conf.SchemeManagers[NewSchemeManagerIdentifier(id)] != nil } -func (_ *SchemeManager) typ() SchemeType { return SchemeTypeIssuer } +func (*SchemeManager) typ() SchemeType { return SchemeTypeIssuer } func (scheme *SchemeManager) purge(conf *Configuration) { id := scheme.Identifier() @@ -1375,7 +1366,7 @@ func (scheme *RequestorScheme) parseContents(conf *Configuration) error { return nil } -func (scheme *RequestorScheme) validate(conf *Configuration) (error, SchemeManagerStatus) { +func (scheme *RequestorScheme) validate(conf *Configuration) (SchemeManagerStatus, error) { // Verify all files in index, reading the RequestorChunks var ( requestors []*RequestorInfo @@ -1390,14 +1381,14 @@ func (scheme *RequestorScheme) validate(conf *Configuration) (error, SchemeManag var currentChunk RequestorChunk exists, err = conf.parseSchemeFile(scheme, file[len(scheme.id())+1:], ¤tChunk) if !exists { - return errors.Errorf("file %s of requestor scheme %s in index but not found on disk", file, scheme.ID), SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, errors.Errorf("file %s of requestor scheme %s in index but not found on disk", file, scheme.ID) } if err != nil { - return err, SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, err } for _, v := range currentChunk { if v.Scheme != scheme.ID { - return errors.Errorf("Requestor %s has incorrect scheme %s", v.Name, v.Scheme), SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, errors.Errorf("Requestor %s has incorrect scheme %s", v.Name, v.Scheme) } } @@ -1410,14 +1401,14 @@ func (scheme *RequestorScheme) validate(conf *Configuration) (error, SchemeManag requestor.Languages = scheme.Languages } if scheme.Demo && len(requestor.Hostnames) > 0 { - return errors.New("Demo requestor has hostnames: only allowed for non-demo schemes"), SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, errors.New("Demo requestor has hostnames: only allowed for non-demo schemes") } if requestor.ID.RequestorSchemeIdentifier() != scheme.ID { - return errors.Errorf("requestor %s has incorrect ID", requestor.ID), SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, errors.Errorf("requestor %s has incorrect ID", requestor.ID) } if requestor.Logo != nil { - if err, status := scheme.checkLogo(conf, *requestor.Logo); err != nil { - return err, status + if status, err := scheme.checkLogo(conf, *requestor.Logo); err != nil { + return status, err } } for id, wizard := range requestor.Wizards { @@ -1425,14 +1416,14 @@ func (scheme *RequestorScheme) validate(conf *Configuration) (error, SchemeManag wizard.Languages = requestor.Languages } if id != wizard.ID || id.RequestorIdentifier() != requestor.ID { - return errors.Errorf("issue wizard %s has incorrect ID", id), SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, errors.Errorf("issue wizard %s has incorrect ID", id) } if err = wizard.Validate(conf); err != nil { - return errors.Errorf("issue wizard %s: %w", id, err), SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, errors.Errorf("issue wizard %s: %w", id, err) } if wizard.Logo != nil { - if err, status := scheme.checkLogo(conf, *wizard.Logo); err != nil { - return err, status + if status, err := scheme.checkLogo(conf, *wizard.Logo); err != nil { + return status, err } path := filepath.Join(scheme.path(), "assets", *wizard.Logo+".png") wizard.LogoPath = &path @@ -1441,19 +1432,19 @@ func (scheme *RequestorScheme) validate(conf *Configuration) (error, SchemeManag } scheme.requestors = requestors - return nil, SchemeManagerStatusValid + return SchemeManagerStatusValid, nil } -func (scheme *RequestorScheme) checkLogo(conf *Configuration, logo string) (error, SchemeManagerStatus) { +func (scheme *RequestorScheme) checkLogo(conf *Configuration, logo string) (SchemeManagerStatus, error) { var hash []byte hash, err := hex.DecodeString(logo) if err != nil { - return err, SchemeManagerStatusParsingError + return SchemeManagerStatusParsingError, err } if _, err = conf.readHashedFile(filepath.Join(scheme.path(), "assets", logo+".png"), hash); err != nil { - return err, SchemeManagerStatusInvalidSignature + return SchemeManagerStatusInvalidSignature, err } - return nil, "" + return "", nil } func (scheme *RequestorScheme) update() error { @@ -1543,7 +1534,7 @@ func (scheme *RequestorScheme) present(id string, conf *Configuration) bool { return conf.RequestorSchemes[NewRequestorSchemeIdentifier(id)] != nil } -func (_ *RequestorScheme) typ() SchemeType { return SchemeTypeRequestor } +func (*RequestorScheme) typ() SchemeType { return SchemeTypeRequestor } // purge removes a requestor scheme and its requestors from the configuration func (scheme *RequestorScheme) purge(conf *Configuration) { diff --git a/server/api.go b/server/api.go index 11d0600a..8a458af9 100644 --- a/server/api.go +++ b/server/api.go @@ -6,7 +6,6 @@ import ( "crypto/rsa" "encoding/hex" "encoding/json" - "fmt" "io" "net" "net/http" @@ -56,7 +55,8 @@ type LogOptions struct { Response, Headers, From, EncodeBinary bool } -// Remove this when dropping support for legacy pre-condiscon session requests +// LegacySessionResult is a pre-condiscon version of SessionResult. +// Remove this when dropping support for legacy pre-condiscon session requests. type LegacySessionResult struct { Token irma.RequestorToken `json:"token"` Status irma.ServerStatus `json:"status"` @@ -81,7 +81,8 @@ const ( var PostSizeLimit int64 = 10 << 20 // 10 MB -// Remove this when dropping support for legacy pre-condiscon session requests +// Legacy returns a pre-condiscon version of this SessionResult. +// Remove this when dropping support for legacy pre-condiscon session requests. func (r *SessionResult) Legacy() *LegacySessionResult { var disclosed []*irma.DisclosedAttribute for _, l := range r.Disclosed { @@ -379,7 +380,7 @@ func log(level logrus.Level, err error) error { if e, ok := err.(*errors.Error); ok && Logger.IsLevelEnabled(logrus.DebugLevel) { _, _ = writer.Write([]byte(e.ErrorStack())) } else { - _, _ = writer.Write([]byte(fmt.Sprintf("%s", err.Error()))) + _, _ = writer.Write([]byte(err.Error())) } return err } diff --git a/server/api_test.go b/server/api_test.go index 4cce1a0e..51a0261c 100644 --- a/server/api_test.go +++ b/server/api_test.go @@ -117,7 +117,7 @@ func TestServerTimeouts(t *testing.T) { defer common.Close(r.Body) // check that reading has halted with an error just after the deadline require.Error(t, err) - require.Greater(t, int64(timeout+50*time.Millisecond), int64(time.Now().Sub(start))) + require.Greater(t, int64(timeout+50*time.Millisecond), int64(time.Since(start))) w.WriteHeader(400) }), body: readerFunc(func(p []byte) (int, error) { @@ -145,7 +145,7 @@ func TestServerTimeouts(t *testing.T) { // Check whether an error is returned when the context deadline exceeds and the handler // does not act upon this within 200 ms. We add 50 ms slack to prevent race conditions. - require.Greater(t, int64(timeout+250*time.Millisecond), int64(time.Now().Sub(start))) + require.Greater(t, int64(timeout+250*time.Millisecond), int64(time.Since(start))) require.GreaterOrEqual(t, res.StatusCode, 400) require.True(t, called) }) diff --git a/server/irmaserver/handle.go b/server/irmaserver/handle.go index 9ae70f06..04f35a26 100644 --- a/server/irmaserver/handle.go +++ b/server/irmaserver/handle.go @@ -620,5 +620,4 @@ func (s *Server) handleRevocationPostIssuanceRecord(w http.ResponseWriter, r *ht server.WriteBinaryResponse(w, nil, server.RemoteError(server.ErrorRevocation, err.Error())) } w.WriteHeader(200) - return } diff --git a/server/irmaserver/helpers.go b/server/irmaserver/helpers.go index a60b51ad..a9198661 100644 --- a/server/irmaserver/helpers.go +++ b/server/irmaserver/helpers.go @@ -129,22 +129,25 @@ func (session *session) fail(err server.Error, message string) *irma.RemoteError } func (session *session) chooseProtocolVersion(minClient, maxClient *irma.ProtocolVersion) (*irma.ProtocolVersion, error) { - // Set minimum supported version to 2.5 if condiscon compatibility is required - minServer := minProtocolVersion - if !session.LegacyCompatible { - minServer = &irma.ProtocolVersion{Major: 2, Minor: 5} - } - // Set minimum to 2.6 if nonrevocation is required - if len(session.request.Base().Revocation) > 0 { - minServer = &irma.ProtocolVersion{Major: 2, Minor: 6} - } - // Set minimum to 2.7 if chained session are used - if session.Rrequest.Base().NextSession != nil { - minServer = &irma.ProtocolVersion{Major: 2, Minor: 7} + minSessionProtocolVersion := minSecureProtocolVersion + if AcceptInsecureProtocolVersions { + // Set minimum supported version to 2.5 if condiscon compatibility is required + minSessionProtocolVersion = minProtocolVersion + if !session.LegacyCompatible { + minSessionProtocolVersion = &irma.ProtocolVersion{Major: 2, Minor: 5} + } + // Set minimum to 2.6 if nonrevocation is required + if len(session.request.Base().Revocation) > 0 { + minSessionProtocolVersion = &irma.ProtocolVersion{Major: 2, Minor: 6} + } + // Set minimum to 2.7 if chained session are used + if session.Rrequest.Base().NextSession != nil { + minSessionProtocolVersion = &irma.ProtocolVersion{Major: 2, Minor: 7} + } } - if minClient.AboveVersion(maxProtocolVersion) || maxClient.BelowVersion(minServer) || maxClient.BelowVersion(minClient) { - err := errors.Errorf("Protocol version negotiation failed, min=%s max=%s minServer=%s maxServer=%s", minClient.String(), maxClient.String(), minServer.String(), maxProtocolVersion.String()) + if minClient.AboveVersion(maxProtocolVersion) || maxClient.BelowVersion(minSessionProtocolVersion) || maxClient.BelowVersion(minClient) { + err := errors.Errorf("Protocol version negotiation failed, min=%s max=%s minServer=%s maxServer=%s", minClient.String(), maxClient.String(), minSessionProtocolVersion.String(), maxProtocolVersion.String()) _ = server.LogWarning(err) return nil, err } diff --git a/server/irmaserver/sessions.go b/server/irmaserver/sessions.go index 6014832d..da30b87c 100644 --- a/server/irmaserver/sessions.go +++ b/server/irmaserver/sessions.go @@ -119,8 +119,13 @@ const ( ) var ( - minProtocolVersion = irma.NewVersion(2, 4) - maxProtocolVersion = irma.NewVersion(2, 9) + // AcceptInsecureProtocolVersions determines whether the server accepts connections from apps using an insecure protocol version. + // It is set to false by default, but can be set to true for backwards compatibility with older apps. This is not recommended. + AcceptInsecureProtocolVersions = false + + minProtocolVersion = irma.NewVersion(2, 4) + minSecureProtocolVersion = irma.NewVersion(2, 8) + maxProtocolVersion = irma.NewVersion(2, 9) minFrontendProtocolVersion = irma.NewVersion(1, 0) maxFrontendProtocolVersion = irma.NewVersion(1, 1) diff --git a/server/keyshare/email.go b/server/keyshare/email.go index 38286c3f..b8a01471 100644 --- a/server/keyshare/email.go +++ b/server/keyshare/email.go @@ -100,7 +100,6 @@ func (conf EmailConfiguration) SendEmail( fmt.Fprintf(&message, "From: %s\r\n", from.Address) fmt.Fprintf(&message, "Subject: %s\r\n", conf.TranslateString(subjects, lang)) fmt.Fprintf(&message, "Content-Type: text/html; charset=UTF-8\r\n") - fmt.Fprintf(&message, "Content-Transfer-Encoding: binary\r\n") fmt.Fprintf(&message, "\r\n") fmt.Fprint(&message, content.String()) diff --git a/server/keyshare/keyshareserver/server.go b/server/keyshare/keyshareserver/server.go index ad208880..1cd56bd0 100644 --- a/server/keyshare/keyshareserver/server.go +++ b/server/keyshare/keyshareserver/server.go @@ -315,7 +315,6 @@ func (s *Server) handleCommitmentsV2(w http.ResponseWriter, r *http.Request) { } commitments, err := s.generateCommitmentsV2(user, authorization, req) - // TODO: can ErrInvalidChallenge be removed? if err != nil && (err == keysharecore.ErrInvalidChallenge || err == keysharecore.ErrInvalidJWT) { server.WriteError(w, server.ErrorInvalidRequest, err.Error()) return @@ -338,7 +337,6 @@ func (s *Server) generateCommitmentsV2(user *User, authorization string, req irm } // Prepare output message format - // TODO: move logic to gabi? mappedCommitments := map[irma.PublicKeyIdentifier]*big.Int{} for i, keyID := range req.Keys { mappedCommitments[keyID] = commitments[i].Pcommit @@ -887,9 +885,7 @@ func (s *Server) authorizationMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Extract authorization from request authorization := r.Header.Get("Authorization") - if strings.HasPrefix(authorization, "Bearer ") { - authorization = authorization[7:] - } + authorization = strings.TrimPrefix(authorization, "Bearer ") // verify access ctx := r.Context() diff --git a/server/keyshare/myirmaserver/postgresdb.go b/server/keyshare/myirmaserver/postgresdb.go index 04bcc201..c4553765 100644 --- a/server/keyshare/myirmaserver/postgresdb.go +++ b/server/keyshare/myirmaserver/postgresdb.go @@ -177,6 +177,7 @@ func (db *postgresDB) verifyLoginToken(ctx context.Context, token, username stri func (db *postgresDB) user(ctx context.Context, id int64) (user, error) { var result user + revalidation := db.db.EmailRevalidation(ctx) // fetch username err := db.db.QueryUserContext(ctx, "SELECT username, language, (coredata IS NULL) AS delete_in_progress FROM irma.users WHERE id = $1", @@ -188,7 +189,7 @@ func (db *postgresDB) user(ctx context.Context, id int64) (user, error) { query := "SELECT email, (delete_on IS NOT NULL) AS delete_in_progress {{revalidate}} FROM irma.emails WHERE user_id = $1 AND (delete_on >= $2 OR delete_on IS NULL)" - if db.db.EmailRevalidation(ctx) { + if revalidation { query = strings.ReplaceAll(query, "{{revalidate}}", ", (revalidate_on IS NOT NULL) AS revalidate_in_progress") } else { query = strings.ReplaceAll(query, "{{revalidate}}", "") @@ -200,7 +201,13 @@ func (db *postgresDB) user(ctx context.Context, id int64) (user, error) { query, func(rows *sql.Rows) error { var email userEmail - err = rows.Scan(&email.Email, &email.DeleteInProgress, &email.RevalidateInProgress) + + if revalidation { + err = rows.Scan(&email.Email, &email.DeleteInProgress, &email.RevalidateInProgress) + } else { + err = rows.Scan(&email.Email, &email.DeleteInProgress) + } + result.Emails = append(result.Emails, email) return err }, diff --git a/staticcheck.conf b/staticcheck.conf new file mode 100644 index 00000000..35df58f2 --- /dev/null +++ b/staticcheck.conf @@ -0,0 +1,4 @@ +checks = ["all", "-ST1000", "-ST1003", "-SA1029"] + +# In the CI, we suppress the deprecation warnings. We use the following configuration there: +# checks = ["all", "-ST1000", "-ST1003", -SA1019", "-SA1029"] diff --git a/timestamp.go b/timestamp.go index 32aadca4..4e7d9544 100644 --- a/timestamp.go +++ b/timestamp.go @@ -44,7 +44,7 @@ func TimestampRequest(message string, sigs []*big.Int, disclosed [][]*big.Int, n disclosedint := make([][]*gobig.Int, len(disclosed)) dlreps := make([]*gobig.Int, len(disclosed)) var d interface{} = disclosedint - for i, _ := range disclosed { + for i := range disclosed { meta := MetadataFromInt(disclosed[i][1], conf) if meta.CredentialType() == nil { return nil, "", errors.New("Cannot compute timestamp request involving unknown credential types") @@ -99,8 +99,8 @@ func TimestampRequest(message string, sigs []*big.Int, disclosed [][]*big.Int, n return hashed[:], timestampServerUrl, nil } -// Given an SignedMessage, verify the timestamp over the signed message, disclosed attributes, -// and rerandomized CL-signatures. +// VerifyTimestamp verifies the timestamp over the signed message, disclosed attributes, +// and rerandomized CL-signatures of the given SignedMessage. func (sm *SignedMessage) VerifyTimestamp(message string, conf *Configuration) error { // Extract the disclosed attributes and randomized CL-signatures from the proofs in order to // construct the nonce that should be signed by the timestamp server. diff --git a/verify.go b/verify.go index 1b94659e..142b44d6 100644 --- a/verify.go +++ b/verify.go @@ -15,7 +15,7 @@ import ( // ProofStatus is the status of the complete proof type ProofStatus string -// Status is the proof status of a single attribute +// AttributeProofStatus is the proof status of a single attribute type AttributeProofStatus string const ( @@ -54,9 +54,7 @@ func (pl ProofList) ExtractPublicKeys(configuration *Configuration) ([]*gabikeys var publicKeys = make([]*gabikeys.PublicKey, 0, len(pl)) for _, v := range pl { - switch v.(type) { - case *gabi.ProofD: - proof := v.(*gabi.ProofD) + if proof, ok := v.(*gabi.ProofD); ok { metadata := MetadataFromInt(proof.ADisclosed[1], configuration) // index 1 is metadata attribute publicKey, err := metadata.PublicKey() if err != nil { @@ -66,7 +64,7 @@ func (pl ProofList) ExtractPublicKeys(configuration *Configuration) ([]*gabikeys return nil, ErrMissingPublicKey } publicKeys = append(publicKeys, publicKey) - default: + } else { return nil, errors.New("Cannot extract public key, not a disclosure proofD") } } diff --git a/version.go b/version.go index fc1874da..6bd8c962 100644 --- a/version.go +++ b/version.go @@ -5,4 +5,4 @@ package irma // Version of the IRMA command line and libraries -const Version = "0.12.6" +const Version = "0.13.2" diff --git a/wait_status.go b/wait_status.go index 4b3d75d6..23c4e38f 100644 --- a/wait_status.go +++ b/wait_status.go @@ -68,7 +68,6 @@ func poll(transport *HTTPTransport, initialStatus ServerStatus, statuschan chan errorchan <- nil return } - break case err := <-errorchanPolling: if err != nil { errorchan <- err