Skip to content

Conversation

@techamateur
Copy link

Resolves #2036

What

  • Added REPORT button next to DETAILS in connection error dialog.
  • Automated sending of failure details (error message, access key, user AS) to a configurable webhook.

Why

  • Manual error reporting via screenshots is inefficient and underutilized.
  • Enables providers to collect real-time connectivity issues data.

How to Test

  1. Add webhook parameter in your access key (e.g., ss://...?&webhook=https://example.com/report#key).
  2. Simulate connection failure (e.g., block server IP).
  3. Click REPORT and verify webhook receives JSON payload:

Screenshot
Error dialog with REPORT button

@techamateur techamateur requested a review from a team as a code owner April 27, 2025 15:20
@fortuna
Copy link
Collaborator

fortuna commented Apr 28, 2025

Thank you for your contribution.

Snackbars should have only one action (with an optional dismiss): https://m3.material.io/components/snackbar/guidelines#ae0935b0-a14e-4dec-8c3c-2c0809acffeb.

This needs a redesign.

@emohandesi
Copy link
Contributor

Thank you for your contribution.

Snackbars should have only one action (with an optional dismiss): https://m3.material.io/components/snackbar/guidelines#ae0935b0-a14e-4dec-8c3c-2c0809acffeb.

This needs a redesign.

@techamateur,
Please refer to #2036 for the updated design. The REPORT button is now moved to the Error Details dialogue box. Please update the screenshot in the PR, too.

Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution 👍. Before we review the code, please clean up the translation files, as they are handled automatically by our pipeline.

@emohandesi
Copy link
Contributor

@fortuna @jyyi1,
This PR is ready to be reviewed.

@emohandesi
Copy link
Contributor

Please add GitHub Copilot as a reviewer.
https://www.youtube.com/watch?v=cyPaAkRfEBQ

Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. But before we get into a detailed review, I'd like to pause and align on the overall design, as I have a few questions on the current approach:

  1. The current design seems to cover manual connection errors. How would we handle reporting for other cases, like automatic reconnection failures? Also, what if the internet is down and we failed to send the report?

  2. The &webhook= parameter works well for URL-based keys. How would this be configured for other formats, like a YAML key? Could you please provide some example keys?

  3. To keep our client code simple, the parsing and handling of this reporting logic feels better suited for the Go layer rather than TypeScript. And it's also very hard for TypeScript to correctly parse an access key (considering we already have URL, JSON and YAML key formats).

  4. Could you clarify what data would be sent in the report? We need to be careful to avoid sending any private user information and prevent any potential misuse of the webhook URL. What if the error details include user sensitive data?

… to fix Go and test issues, install Android Build Tools 35.0.0, fix TypeScript and Mocha issues, Revert files that shouldn't have changed
@emohandesi
Copy link
Contributor

emohandesi commented Sep 21, 2025

Most of these questions have been answered in #2484 (comment). I am adding a few more points.

Thanks for the PR. But before we get into a detailed review, I'd like to pause and align on the overall design, as I have a few questions on the current approach:

  1. The current design seems to cover manual connection errors. How would we handle reporting for other cases, like automatic reconnection failures? Also, what if the internet is down and we failed to send the report?

  2. The &webhook= parameter works well for URL-based keys. How would this be configured for other formats, like a YAML key? Could you please provide some example keys?

Sample keys are shown in #2036. The following can be a sample YAML key. Adding the webhook as a parameter in the URL rather than adding the webhook to the content of the YAML key has the benefit of being able to report the failure in fetching the key. Therefore, we decided to use this syntax.
ssconf://sarvar.s3.us-east-1.amazonaws.com/sw/FqxieR8q2PgyJ3ciPtWaVp?webhook=webhook.site/ad6c8c36-35e5-4f0a-9eb0-d95c071ca3d1#Poland

  1. To keep our client code simple, the parsing and handling of this reporting logic feels better suited for the Go layer rather than TypeScript. And it's also very hard for TypeScript to correctly parse an access key (considering we already have URL, JSON and YAML key formats).

As mentioned in the response to your 2nd question, the plan is not to parse the YAML key content and webhook is retrieved from the key URL.

  1. Could you clarify what data would be sent in the report? We need to be careful to avoid sending any private user information and prevent any potential misuse of the webhook URL. What if the error details include user sensitive data?

"version": "ቅጂ {appVersion}",
"yes": "አዎ"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not show any change in this file, but this is still shown in the changes. Can you please revert these changes in a way so that we would not see any changes in the files located in client/src/www/messages/?

@fortuna
Copy link
Collaborator

fortuna commented Oct 13, 2025

I have some privacy concerns about this design. It can reveal the user ID (from the key), and the user IP (from the error), which will in turn get logged somewhere. And the user probably has no idea of what information they are leaking.

You don't really need that information. For example, the "webhook" could be something like https://report.example.com?endpoint=ol.server.com:4006&proto=ss&prefix=POST%20 (really any info you want, but respecting user privacy)
If you want to send errors, they will have to be sanitized. For example, by just getting the error types or marking "safe" strings/errors.

Also, let's rename webhook to report-to so it's clear what it is.

@emohandesi
Copy link
Contributor

I have some privacy concerns about this design. It can reveal the user ID (from the key), and the user IP (from the error), which will in turn get logged somewhere. And the user probably has no idea of what information they are leaking.

The key provider has numerous methods to get the user IP such as through the VPN server it provides. Whenever the user tries to connect to a VPN server, its IP is revealed; therefore, this reporting mechanism is not the only place that reveals the user IP. The key provider can also use tools that sit in between the user and the Outline server that just forward the traffic while collecting user IP and similar information.
The user key is needed in the report because when a user says they have reported an issue, we want to know which key is having the problem and update the user regarding the issue they are facing, such as recommending to change the ISP or outdated key, etc.

You don't really need that information. For example, the "webhook" could be something like https://report.example.com?endpoint=ol.server.com:4006&proto=ss&prefix=POST%20 (really any info you want, but respecting user privacy)

The webhook link used here can be any type of link and does not necessarily need to be a link to webhook.site. Outline just posts a cURL request to that link to send the error information.

If you want to send errors, they will have to be sanitized. For example, by just getting the error types or marking "safe" strings/errors.

The goal of this feature is to send as much error information as possible to better help the provider to come up with a solution for the error message faced.

Also, let's rename webhook to report-to so it's clear what it is.

That is a good suggestion. I guess this is reasonable to use a more universal name such as report-to.

@fortuna
Copy link
Collaborator

fortuna commented Oct 23, 2025

We discussed this in a meeting. The main issues are that both the strategy and the error messages can contain PII (e.g. credentials -> user id, user IP address), so BOTH need to be sanitized.

For reporting the strategy, I'd favor fixing some sort of strategy ID or tags. (e.g. shadowsocks-80-http, ws-over-ss). That could be hardcoded in the report parameter. Alternatively, we can do a best-effort sanitization that "fails closed" in case a strategy lacks implementation.

For the errors, we should come up with a mechanism to ensure they are free of PII. That can be tricky. At a minimum, we should sanitize it to redact any reference to hostnames or IPs (v4 and v6), perhaps host:port.

I'd prefer to have the reporting config after the #, since that's more of a service config, not the transport.

@techamateur
Copy link
Author

Thank you for your thoughtful comment.

We discussed this in a meeting. The main issues are that both the strategy and the error messages can contain PII (e.g. credentials -> user id, user IP address), so BOTH need to be sanitized.

All PII can be sanitized using the Outline’s existing functions and any new changes that need to be introduced, but the user’s IP cannot be hidden as it is the IP that sends the report.

For reporting the strategy, I'd favor fixing some sort of strategy ID or tags. (e.g. shadowsocks-80-http, ws-over-ss). That could be hardcoded in the report parameter. Alternatively, we can do a best-effort sanitization that "fails closed" in case a strategy lacks implementation.

Yes, this is possible, but as explained later, the VPN provider can use separate report receivers for different servers and easily find out which key a report corresponds to.

For the errors, we should come up with a mechanism to ensure they are free of PII. That can be tricky. At a minimum, we should sanitize it to redact any reference to hostnames or IPs (v4 and v6), perhaps host:port.

Removing the hostname will defeat the purpose of this feature. The main purpose of reporting the error message is to let the VPN provider which VPN server has a problem. If the VPN provider receives only an error message, then it is not useful in most scenarios because the VPN provider does not know which one of its servers has a problem.

However, the VPN provider can provide a different reporting address for each of their VPN servers. Therefore, they can identify which VPN server a report corresponds to.

I'd prefer to have the reporting config after the #, since that's more of a service config, not the transport.

This is a sample key: ssconf://domain.com/password#Key_name
We can put the the report-to part either before or after the #:

  1. ssconf://domain.com/password&report-to:reportingserver.com#Key_name
  2. ssconf://domain.com/password#Key_name&report-to:reportingserver.com
  3. ssconf://domain.com/password#report-to:reportingserver.com&Key_name

Using either of the 2nd and the 3rd formats changes the Outlines assumption that everything that goes after # is the key name. We can, of course, use any of the formats in 2 and 3, but it seems format 1 fits better with the current Outline standards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable user to report the connection failure

5 participants