The Tor Project issueshttps://gitlab.torproject.org/groups/tpo/-/issues2024-03-06T18:39:12Zhttps://gitlab.torproject.org/tpo/applications/tor-browser/-/issues/42436Allow for multiple configured (front, reflector) domain fronting pairs in Moa...2024-03-06T18:39:12ZCecylia BocovichAllow for multiple configured (front, reflector) domain fronting pairs in Moat moduleIt's happened twice now that the domain fronting settings for Moat have stopped working:
- [when `cdn.sstatic.net` moved to CloudFlare](https://lists.torproject.org/pipermail/anti-censorship-team/2023-September/000314.html)
- [when Fastl...It's happened twice now that the domain fronting settings for Moat have stopped working:
- [when `cdn.sstatic.net` moved to CloudFlare](https://lists.torproject.org/pipermail/anti-censorship-team/2023-September/000314.html)
- [when Fastly stopped supporting domain fronting and `foursquare.com` renewed its cert](https://github.com/net4people/bbs/issues/309)
When Moat stops working, it leaves us scrambling to find new front domains, the update process requires a new release, and it can be difficult for users to receive updates or connect if Connection Assist is unreachable. It's also difficult to choose a single front domain that will work in almost every place. Even though Connect Assist allows us offer country-specific circumvention settings, we have only a single setting for using Connect Assist itself.
Ideally, we could provide multiple (front, reflector) pairs, and iterate through them until a working pair is found. That pair can be saved for future use until it stops working and the module will re-iterate through the list until a new pair is found.https://gitlab.torproject.org/tpo/tpa/gitlab/-/issues/151Encrypt confidential emails2024-03-06T18:30:32Zmicahmicah@torproject.orgEncrypt confidential emailsNow that [confidential issue emails are not sent in the clear](https://gitlab.torproject.org/tpo/tpa/gitlab/-/issues/23) it might be interesting to consider what it would take to modify the current process so that it sent encrypted email...Now that [confidential issue emails are not sent in the clear](https://gitlab.torproject.org/tpo/tpa/gitlab/-/issues/23) it might be interesting to consider what it would take to modify the current process so that it sent encrypted emails with the actual contents of the issue, if possible.
We could modify the python script that was deployed to redact the message to add a few additional steps: query the gitlab API (requires a personal access token) to look up a user's ID, and then lookup that ID's OpenPGP key. If they have one set, then encrypt the mail to them, and if they do not, then do what we do now (send the "This issue is confidential and the contents of the message have been redacted." message).
Its actually quite easy to get the public key of a user via the API, if you know their email address. To figure out how, I wrote this script that will spit out the OpenPGP key of any email in gitlab *as long as the user's email is public*:
```python
import argparse
import requests
import sys
GITLAB_API_URL = 'https://gitlab.torproject.org/api/v4'
GITLAB_PRIVATE_TOKEN = '<redacted>'
def get_user_id(email):
"""Fetch the GitLab user ID based on the email address."""
headers = {'Private-Token': GITLAB_PRIVATE_TOKEN}
try:
response = requests.get(f"{GITLAB_API_URL}/users?search={email}", headers=headers)
response.raise_for_status() # Raises an HTTPError if the response code was unsuccessful
users = response.json()
if not users:
print(f"API returned no users for email: {email}")
return None
return users[0]['id']
except requests.exceptions.HTTPError as e:
print(f"HTTPError: {e.response.status_code} {e.response.reason}")
except requests.exceptions.RequestException as e:
print(f"RequestException: {e}")
return None
def get_user_gpg_keys(user_id):
"""Fetch the GPG keys associated with a GitLab user ID."""
headers = {'Private-Token': GITLAB_PRIVATE_TOKEN}
try:
response = requests.get(f"{GITLAB_API_URL}/users/{user_id}/gpg_keys", headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
print(f"HTTPError: {e.response.status_code} {e.response.reason}")
except requests.exceptions.RequestException as e:
print(f"RequestException: {e}")
return []
def main():
parser = argparse.ArgumentParser(description='Fetch a GitLab user\'s GPG key by email address.')
parser.add_argument('email', type=str, help='The email address of the user to search for.')
args = parser.parse_args()
user_id = get_user_id(args.email)
if not user_id:
sys.exit("Exiting: No user found or error occurred.")
gpg_keys = get_user_gpg_keys(user_id)
if not gpg_keys:
print(f"No GPG keys found for user with ID {user_id}")
return
for key in gpg_keys:
print(f"{key['key']}")
if __name__ == "__main__":
main()
```
Considering that is how you would pull the key from the API endpoint, then you could imagine modifying the existing deployed script to incorporate this. Here is some *untested* somewhat pseudo-code modification of the currently deployed script. Because I can't test this, there are some obvious things that are wrong, but the basic idea is there:
```python
#!/usr/bin/python3 -X utf8
import argparse
from email.parser import Parser
import email.policy
from io import StringIO
import logging
import quopri
from typing import TextIO
import subprocess
import sys
import requests
import gnupg
gpg = gnupg.GPG(gnupghome='/path/to/.gnupg')
gitlab_api_url = 'https://gitlab.torproject.org/api/v4'
gitlab_private_token = 'prviate access token'
def get_user_gpg_key(email):
"""Fetch the user's GPG key from GitLab API."""
headers = {'Private-Token': gitlab_private_token}
users = requests.get(f"{gitlab_api_url}/users?search={email}", headers=headers).json()
if not users:
return None
user_id = users[0]['id']
keys = requests.get(f"{gitlab_api_url}/users/{user_id}/gpg_keys", headers=headers).json()
if not keys:
return None
return keys[0]['key']
def encrypt_message(message, gpg_key):
"""Encrypt the message with the provided GPG key."""
imported_key = gpg.import_keys(gpg_key)
encrypted_data = gpg.encrypt(message, imported_key.fingerprints[0], always_trust=True)
return str(encrypted_data)
def main():
logging.basicConfig(level="INFO", format="%(levelname)s: %(message)s")
parser = argparse.ArgumentParser()
parser.add_argument("--stdout", action="store_true", help="send the email to stdout instead of sendmail(1)")
parser.add_argument("--from", "-f", dest="sender", help="sender address")
parser.add_argument("recipients", nargs="+", help="recipient address(es)")
args = parser.parse_args()
email_content = transform_email(sys.stdin, args.recipients[0]) # Assuming one recipient for simplicity
if args.stdout:
print(email_content)
else:
cmd = ["/usr/sbin/sendmail", "-G", "-i", "-f", args.sender, "--"] + args.recipients
try:
subprocess.Popen(cmd, stdin=subprocess.PIPE, encoding="utf-8").communicate(email_content)
except Exception as e:
import traceback
print("4.3.0 %s: %s" % (e, traceback.format_exc()))
sys.exit(75) # TEMPFAIL
def transform_email(stream: TextIO, recipient_email):
msg = Parser(policy=email.policy.compat32).parse(stream)
if msg.get('X-GitLab-ConfidentialIssue', 'false') != 'true':
return str(msg)
gpg_key = get_user_gpg_key(recipient_email)
if gpg_key:
# Encrypt the message if a GPG key is found
encrypted_msg = encrypt_message(str(msg), gpg_key)
return encrypted_msg
else:
# Redact if no GPG key is found
for part in msg.walk():
if part.is_multipart():
continue
if part.get_content_type() != 'text/plain':
continue
plain_text = part.as_string()
signature = quopri.decodestring(plain_text.split("-- ").pop()).decode("ascii")
redaction_msg = """This issue is confidential and the contents of the message have been redacted.
--
""" + signature
del msg['X-GitLab-ConfidentialIssue']
msg['X-GitLab-ConfidentialIssue'] = 'redacted'
msg.set_type("text/plain")
msg.del_param("boundary", header="Content-Type")
msg.set_payload(redaction_msg)
return str(msg)
if __name__ == "__main__":
main()
```https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40340Add a mechanism to retest the client NAT type2024-03-04T08:42:02ZCecylia BocovichAdd a mechanism to retest the client NAT typeWhile we do periodically retest the NAT type of proxies, a client's NAT type is only checked once on startup. The result is that if, after the initial check, a client's network conditions change, they may have difficulty connecting to pr...While we do periodically retest the NAT type of proxies, a client's NAT type is only checked once on startup. The result is that if, after the initial check, a client's network conditions change, they may have difficulty connecting to proxies in their pool. Since client usage of snowflake is much more time-sensitive than proxies, the trigger for a retest could be a threshold of a certain number of failed Datachannel attempts.https://gitlab.torproject.org/tpo/applications/tor-browser/-/issues/42429Android Connection Assist Non-Portriat-Phone Sizes Design2024-02-29T00:51:27ZclairehurstAndroid Connection Assist Non-Portriat-Phone Sizes DesignFor tor-browser#41188 we have portrait designs, but don't have landscape (and other non-protrait-phone) designs. How do we want the landscape (and other non-portriat-phone sizes) to look for connection assist? I was messing with trying t...For tor-browser#41188 we have portrait designs, but don't have landscape (and other non-protrait-phone) designs. How do we want the landscape (and other non-portriat-phone sizes) to look for connection assist? I was messing with trying to make it look better and have some references. I made the buttons have a max width, brought the toggle closer to the text, and reduced the spacing for the text so that it fits better horizontally (otherwise views start overlapping on certain screens with enough going on)
Mock Native Landscape
![Mock_Native_Landscape](/uploads/b2f313b9b51ae7a0499b3bfde3d917a7/Mock_Native_Landscape.png)
Current HTML Landscape
![HTML_Landscape](/uploads/6fa173af6b86fa10d8c1db5e072c27da/HTML_Landscape.png)
Mock Tablet
![Mock_Tablet](/uploads/bfc51dbdad8bfc6b6d60ea768e3dfb86/Mock_Tablet.png)
Mock Foldable
![Mock_Foldable](/uploads/38eb8f5c11b61ee47fd8e2c1db3d81be/Mock_Foldable.png)
Current Native Portrait
![Native_Portrait](/uploads/384005393822624e481d9a2e60a3935f/Native_Portrait.png){width=25%}donutsdonutshttps://gitlab.torproject.org/tpo/web/snowflake/-/issues/9unify volunteer instructions from support entry onto snowflake website2024-02-27T14:24:07ZRoger Dingledineunify volunteer instructions from support entry onto snowflake websiteWe have this support entry: <br>
https://support.torproject.org/censorship/how-to-help-running-snowflake/
which tells people to install the Firefox or Chrome extension, or load the embed in a page. It doesn't mention the Edge extension ...We have this support entry: <br>
https://support.torproject.org/censorship/how-to-help-running-snowflake/
which tells people to install the Firefox or Chrome extension, or load the embed in a page. It doesn't mention the Edge extension or the standalone proxy.
Rather than trying to keep both sets of instructions in sync, I think we should put the instructions on the snowflake.torproject.org page, and point to them from a much slimmer support entry.
To achieve this goal, there are currently two things that the support entry says that the snowflake.torproject.org website does not:
* You need to enable WebRTC in your browser, to usefully run the extension or to usefully load the embed. (If we could reliably have the extension or the embed page report that your WebRTC is missing and you need to fix that, then we could get away with not saying it on the webpage. So, feel free to do that instead if it is easier, but I am suspecting it is not easier. :)
* "Due to censorship of VPN servers in some countries, we kindly ask you to not run a snowflake proxy while connected to a VPN" as advised by @cohosh at https://forum.torproject.org/t/running-a-snowflake-proxy-behind-a-vpn-consequences-for-tor-users/2047/4 and then recorded by gus at https://gitlab.torproject.org/tpo/web/support/-/issues/296. Feel free also to change your mind about the "not on a VPN please" advice.
Once we have these two items either make their way onto the snowflake.torproject.org proxy instructions or have you tell us you don't intend to, then we should be all ready to remove the (redundant, already not as correct) text from the support entry.
Thanks!https://gitlab.torproject.org/tpo/community/support/-/issues/40145Update support documentation for Tor Browser 13.5 release2024-02-27T03:19:59Zebanamebanam@torproject.orgUpdate support documentation for Tor Browser 13.5 releaseUpdate articles on RT and text modules on cdr.link with the Tor Browser 13.5 release.
related: https://gitlab.torproject.org/tpo/web/manual/-/issues/155
/cc @nina @gusUpdate articles on RT and text modules on cdr.link with the Tor Browser 13.5 release.
related: https://gitlab.torproject.org/tpo/web/manual/-/issues/155
/cc @nina @gusebanamebanam@torproject.orgebanamebanam@torproject.orghttps://gitlab.torproject.org/tpo/web/manual/-/issues/155Update Tor Browser User Manual for the Tor Browser 13.5 release2024-03-18T17:24:36Zebanamebanam@torproject.orgUpdate Tor Browser User Manual for the Tor Browser 13.5 releaseTor Browser tickets for Tor Browser stable 13.5: https://gitlab.torproject.org/tpo/applications/tor-browser/-/issues/?label_name%5B%5D=13.5%20stableTor Browser tickets for Tor Browser stable 13.5: https://gitlab.torproject.org/tpo/applications/tor-browser/-/issues/?label_name%5B%5D=13.5%20stableebanamebanam@torproject.orgebanamebanam@torproject.orghttps://gitlab.torproject.org/tpo/applications/torbrowser-launcher/-/issues/16Transition away from deprecated python distutils2024-03-05T13:57:46Zmicahmicah@torproject.orgTransition away from deprecated python distutilsIn Python 3.10 and 3.11, distutils has been formally marked as deprecated. Code that imports distutils will no longer work from Python 3.12.
Please prepare for this deprecation and migrate away from the Python distutils module.
See-Als...In Python 3.10 and 3.11, distutils has been formally marked as deprecated. Code that imports distutils will no longer work from Python 3.12.
Please prepare for this deprecation and migrate away from the Python distutils module.
See-Also: https://peps.python.org/pep-0632https://gitlab.torproject.org/tpo/web/tpo/-/issues/420Press mentions for 2022 - 2023 needed on website2024-03-12T00:32:37ZemmapeelPress mentions for 2022 - 2023 needed on websiteOur [Press](https://www.torproject.org/press/) page shows articles up until 2021-12-29.Our [Press](https://www.torproject.org/press/) page shows articles up until 2021-12-29.pavelpavel2024-03-31https://gitlab.torproject.org/tpo/core/arti/-/issues/1292Add service config for enabling client authorization ("restricted mode")2024-03-05T14:43:22Zgabi-250Add service config for enabling client authorization ("restricted mode")* [ ] Choose a name for the `enabled` option, and decide what values it
should take (`BoolOrAuto` may not be the right type for it
* [ ] Implement the service configuration for configuring "restricted" mode
with static `authorize...* [ ] Choose a name for the `enabled` option, and decide what values it
should take (`BoolOrAuto` may not be the right type for it
* [ ] Implement the service configuration for configuring "restricted" mode
with static `authorized_clients`:
```toml
[onion_service."allium-cepa".restricted_mode]
# TODO: The naming and values of this field are provisional
enabled = auto | on | off
[onion_service."allium-cepa".restricted_mode.authorized_clients.static]
alice = "descriptor:x25519:PU63REQUH4PP464E2Y7AVQ35HBB5DXDH5XEUVUNP3KCPNOXZGIBA"
bob = "descriptor:x25519:B5ZQGTPERMMUDA6VC63LHJUF5IHPOKJMUK26LY2XKSF7VG52AESQ"
# Alternatively, you can specify a directory of authorized clients.
# Each authorized client is represented by an .auth file, as specified
# under CLIENT AUTHORIZATION in tor(1).
#
# [onion_service."allium-cepa".restricted_mode.authorized_clients]
# path = "/etc/allium/authorized_clients"
```Arti: Feature parity with the C implementationgabi-250gabi-250https://gitlab.torproject.org/tpo/core/arti/-/issues/1291Support encoding the public part of client auth keys in C Tor format2024-02-21T15:36:36Zgabi-250Support encoding the public part of client auth keys in C Tor formatArti: Feature parity with the C implementationgabi-250gabi-250https://gitlab.torproject.org/tpo/applications/tor-browser/-/issues/42418TorBrowser leave trace on the Windows Event Log by default and there is no wa...2024-03-05T13:50:25ZcypherpunksTorBrowser leave trace on the Windows Event Log by default and there is no way to stop this!To be clear, Mozilla Firefox does same thing.
Steps.
1. Launch Tor Browser latest
2. Open "eventvwr.ms" (The event viewer of Windows)
3. Open "Windows Logs/Application"
You'll see tons of:
```
The description for Event ID 5 from sourc...To be clear, Mozilla Firefox does same thing.
Steps.
1. Launch Tor Browser latest
2. Open "eventvwr.ms" (The event viewer of Windows)
3. Open "Windows Logs/Application"
You'll see tons of:
```
The description for Event ID 5 from source Tor Browser Launcher cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer.
If the event originated on another computer, the display information had to be saved with the event.
The following information was included with the event:
```https://gitlab.torproject.org/tpo/web/lego/-/issues/63upstream lektor-i18n patches2024-02-20T20:04:13Zanarcatupstream lektor-i18n patchesour lektor-i18n-plugin package has diverged from upstream. submit the patches back upstream in the form of a nice PR and offer collaboration.our lektor-i18n-plugin package has diverged from upstream. submit the patches back upstream in the form of a nice PR and offer collaboration.Jérôme Charaouilavamind@torproject.orgJérôme Charaouilavamind@torproject.orghttps://gitlab.torproject.org/tpo/core/arti/-/issues/1288RPC: Safe connection method on windows2024-02-24T18:29:44ZNick MathewsonRPC: Safe connection method on windowsOn Unix, we can use AF_UNIX sockets to make sure that we've got a request from an authorized user. But on Windows, we don't have the equivalent. We shoul build some other authentication mechanism (SSL? Disk Cookie? Windows named pipes)...On Unix, we can use AF_UNIX sockets to make sure that we've got a request from an authorized user. But on Windows, we don't have the equivalent. We shoul build some other authentication mechanism (SSL? Disk Cookie? Windows named pipes) before we ship RPC.https://gitlab.torproject.org/tpo/core/arti/-/issues/1286Double-check implementation for SRV disaster fallback values2024-02-20T17:15:11ZNick MathewsonDouble-check implementation for SRV disaster fallback valuesWe do have a check for our disaster_srv calculation (in `tor_netdir::hsdir_params::test::disaster)`, and its value does seem to match up with the C tor implementation's test value in (`test_hs_common.c:test_disaster_srv()`).
But we shou...We do have a check for our disaster_srv calculation (in `tor_netdir::hsdir_params::test::disaster)`, and its value does seem to match up with the C tor implementation's test value in (`test_hs_common.c:test_disaster_srv()`).
But we should create higher level disaster SRV tests, to make sure that we actually build the same ring that C tor does.
We suspect that this could be related to a bug encountered on a day with the authorities failed to negotiate an SRV (‽).Nick MathewsonNick Mathewsonhttps://gitlab.torproject.org/tpo/core/arti/-/issues/1284Clients should identify services by nickname, not hsid2024-02-21T15:36:38Zgabi-250Clients should identify services by nickname, not hsid * [ ] Add a client-side `ClientSideFooHsNickname` type. Pick a name for it
(it should be distinguishable from the service-side `HsNickname`), define
its charset and decide what limit to impose on its length
* [ ] Add a `Clie... * [ ] Add a client-side `ClientSideFooHsNickname` type. Pick a name for it
(it should be distinguishable from the service-side `HsNickname`), define
its charset and decide what limit to impose on its length
* [ ] Add a `ClientSideFooHsNickname` to the client key specifiers, and make
clients error if there is more than one nickname for any given HsIdArti: Feature parity with the C implementationgabi-250gabi-250https://gitlab.torproject.org/tpo/core/arti/-/issues/1281Implement the arti hsc prepare-stealth-mode-key subcommand2024-02-21T15:36:37Zgabi-250Implement the arti hsc prepare-stealth-mode-key subcommandSee the proposal in https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/1987#note_2996998
* [ ] Pick a name for the subcommand (`prepare-restricted-mode-key`? `prepare-shielded-mode-key`?)
* [ ] Implement the subcommand:
``...See the proposal in https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/1987#note_2996998
* [ ] Pick a name for the subcommand (`prepare-restricted-mode-key`? `prepare-shielded-mode-key`?)
* [ ] Implement the subcommand:
```
arti hsc prepare-stealth-mode-key
--hs[-]nick[name] ... # no default, option has shorter convenience aliases
[ --config arti.toml ] # default is default arti.toml
[ --keystore ... ] # default is `default`; no client nicknames yet
[ --output FOO.auth ] # default is <hs-nickname>.auth, use `-` for stdout
[ --overwrite ] # overwrites any existing output file; default is to refuse
[ --generate=no|yes|if-needed ] # if-needed is the default; otherwise, can error
```
This depends on #1283, #1284 and #1291Arti: Feature parity with the C implementationgabi-250gabi-250https://gitlab.torproject.org/tpo/community/l10n/-/issues/40133Separate translation contributions per person in the commits, just in case2024-02-13T13:27:07ZemmapeelSeparate translation contributions per person in the commits, just in caseWatching the video at https://fosdem.org/2024/schedule/event/fosdem-2024-1906-lessons-learnt-as-a-translation-contributor-the-past-4-years/ I think I need to change the configuration of our components in weblate.
To save space, and bec...Watching the video at https://fosdem.org/2024/schedule/event/fosdem-2024-1906-lessons-learnt-as-a-translation-contributor-the-past-4-years/ I think I need to change the configuration of our components in weblate.
To save space, and because I can see this information in weblate if I need it, I was squashing translators contributions in weblate all together in one commit. But if a translator would want to remove its contributions, it will be a very difficult thing to do. So it is better to separate the contributions and have one commit per person.emmapeelemmapeelhttps://gitlab.torproject.org/tpo/core/arti/-/issues/1273Implement vanguard pool persistence2024-02-21T17:48:29Zgabi-250Implement vanguard pool persistenceThe pools will likely be stored in the state dir.
This is a prerequisite to implementing vanguards-fullThe pools will likely be stored in the state dir.
This is a prerequisite to implementing vanguards-fullArti: Guard discovery researchgabi-250gabi-250https://gitlab.torproject.org/tpo/core/arti/-/issues/1272Add vanguard configuration options2024-03-26T14:59:04Zgabi-250Add vanguard configuration optionsWe have a few options here:
* have a single, global configuration option the says whether to use
vanguards-lite, or vanguards-full. This would apply to all HS
circuits (to both client and service circuits)
* have separate con...We have a few options here:
* have a single, global configuration option the says whether to use
vanguards-lite, or vanguards-full. This would apply to all HS
circuits (to both client and service circuits)
* have separate configuration options for clients and services (the
service vanguard config would be per-service). This would enable us
to configure clients and services, as well as different services
running in the same arti instance, independently from each other
(I'm not sure whether this is useful though).
We might also want to add config options for overriding the
`guard-hs-l2-number`, `guard-hs-l2-lifetime-min`, `guard-hs-l2-lifetime-max`
consensus parameters, so perhaps we need a proper `VanguardsConfig` (rather than a
simple `vanguards: auto|lite|full` option)
```toml
[onion_services."allium-cepa".vanguards]
kind = "lite"
l2_guard_num = 5
# TODO: there are no consensus params for the l3 guards
l3_guard_num = 15
...
```Arti: Guard discovery researchgabi-250gabi-250