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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ 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
### Fixed
- `irma.HTTPTransport` now honours the `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` environment variables, so irmago can run where outgoing traffic must pass through a proxy; it was the only outbound transport in irmago that ignored them. Operators with a system-wide proxy can keep internal traffic (requestor callbacks, keyshare and revocation servers) off it with `NO_PROXY`; loopback addresses are never proxied ([#423](https://github.com/privacybydesign/irmago/issues/423))

## [1.3.0] - 2026-08-12
### Added
Expand Down
5 changes: 4 additions & 1 deletion irma/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,11 @@ func NewHTTPTransport(serverURL string, forceHTTPS bool) *HTTPTransport {
}

// Create a transport that dials with a SIGPIPE handler (which is only active on iOS).
// The settings are inspired on the defaults of http.DefaultTransport.
// The settings are inspired on the defaults of http.DefaultTransport, including its
// Proxy: outbound requests honour the HTTP_PROXY, HTTPS_PROXY and NO_PROXY environment
// variables, as the rest of irmago already does through http.DefaultTransport.
innerTransport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: tlsClientConfig,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
Expand Down
26 changes: 26 additions & 0 deletions irma/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -146,3 +147,28 @@ func TestJsonRequest_RemoteErrorBodyIsPreserved(t *testing.T) {
})
}
}

// TestNewHTTPTransport_UsesEnvironmentProxy covers issue #423: HTTPTransport was the
// only outbound transport in irmago that left http.Transport.Proxy unset, so it ignored
// the HTTP_PROXY/HTTPS_PROXY environment variables that everything routed through
// http.DefaultTransport already honours.
//
// The proxy function is inspected directly rather than exercised against a real proxy,
// because net/http reads the environment once behind a sync.Once: a test setting
// HTTP_PROXY would only take effect if it happened to run before any other code in the
// process resolved a proxy.
func TestNewHTTPTransport_UsesEnvironmentProxy(t *testing.T) {
inner, ok := NewHTTPTransport("https://example.com", true).client.HTTPClient.Transport.(*http.Transport)
require.True(t, ok)
require.NotNil(t, inner.Proxy, "outbound transport must honour HTTP_PROXY/HTTPS_PROXY")

// Loopback destinations are never proxied, whatever the environment says, so local
// servers (including the ones in these tests) keep being dialled directly.
for _, dest := range []string{"http://localhost:8080/foo", "http://127.0.0.1:8080/foo"} {
u, err := url.Parse(dest)
require.NoError(t, err)
proxy, err := inner.Proxy(&http.Request{URL: u})
require.NoError(t, err)
require.Nil(t, proxy, "loopback destination %s must not be proxied", dest)
}
}