Compare commits

...

75 Commits

Author SHA1 Message Date
Manav Rathi
99fdbd8d40 photosd-v1.7.1 (#2170) 2024-06-17 13:57:28 +05:30
Manav Rathi
ac4a68d64e photosd-v1.7.1 2024-06-17 13:55:31 +05:30
Manav Rathi
dae5b29ef1 [docs] Add a border to help differentiate the image from the subsequent text (#2169)
Nb: black works fine in dark mode too
2024-06-17 12:24:14 +05:30
Manav Rathi
4451b489e4 Add a border to help differentiate the image from the subsequent text
black works fine in dark mode too
2024-06-17 12:22:47 +05:30
Manav Rathi
b19281ea2b [web] Update cast to use the tsconfig we want (#2168) 2024-06-17 12:08:41 +05:30
Manav Rathi
8e923fe443 All 2024-06-17 11:46:34 +05:30
Manav Rathi
fe47186ace tsc 2024-06-17 11:45:28 +05:30
Manav Rathi
326704a605 tsc 2024-06-17 11:38:13 +05:30
Manav Rathi
d560ed9a33 Reduce state 2024-06-17 11:35:19 +05:30
Manav Rathi
0a8f51832a tsc 2024-06-17 11:34:16 +05:30
Neeraj Gupta
d2112b984d Added coindcx icon (#2148)
## Description
Added coindcx icon
uploaded coindcx svg and updated json file.
2024-06-17 11:24:48 +05:30
Neeraj Gupta
50aad0c5d1 [Auth] Passkey fix for linux (#2154)
## Description

- Updated url to enteauth://passkey
- Support mimetype in appimage so redirection is done properly

## Tests
2024-06-17 11:24:09 +05:30
Manav Rathi
e6e721f0ba [workers] Import upload worker (#2164) 2024-06-17 09:12:15 +05:30
Manav Rathi
80b34f1aef Reduce spurious logs for headers our clients send 2024-06-17 09:03:27 +05:30
Manav Rathi
d5a8586152 Import functionality
Rewritten but referencing the code imported from dashboard
2024-06-17 03:40:20 +05:30
Manav Rathi
bfcd84c940 Whitelist the necessary one 2024-06-16 20:56:28 +05:30
Manav Rathi
a4bc5fa0df OPTIONS 2024-06-16 20:49:44 +05:30
Manav Rathi
ed406e7eb0 Sketch 2024-06-16 20:33:56 +05:30
Manav Rathi
b4dc49ef2f [workers] Import health check worker (#2162) 2024-06-16 19:43:31 +05:30
Manav Rathi
483e3be682 Improvements 2024-06-16 19:40:03 +05:30
Manav Rathi
17f0d77a31 Reorder to fix errors 2024-06-16 19:18:39 +05:30
Manav Rathi
c6f644ef8a [workers] Import health check worker 2024-06-16 19:12:52 +05:30
Prateek Sunal
01b566698f fix(workflow/auth): revert back flutter_distributor to pub.dev source 2024-06-16 17:03:45 +05:30
Manav Rathi
469f884d8c [workers] Import files worker (#2161) 2024-06-16 15:01:26 +05:30
Manav Rathi
9e4412cbee Correct place 2024-06-16 14:52:15 +05:30
Manav Rathi
f4bab262ca Import 2024-06-16 14:47:35 +05:30
Manav Rathi
73fd63616d Sketch 2024-06-16 14:39:05 +05:30
Manav Rathi
9362a4b9d3 Reduce log noise 2024-06-16 14:29:54 +05:30
Manav Rathi
6c5ea59506 [workers] Import thumbnails worker (#2160) 2024-06-16 14:19:02 +05:30
Manav Rathi
90845bdb02 Rename 2024-06-16 14:12:16 +05:30
Manav Rathi
f6729be5ab Fix typo 2024-06-16 14:09:20 +05:30
Manav Rathi
344c5cc399 Desktop origin includes scheme 2024-06-16 14:06:20 +05:30
Manav Rathi
6e1ea29c39 Implement
Rewritten, but referencing the existing worker imported from the dashboard
2024-06-16 13:51:42 +05:30
Manav Rathi
d76c6dd63c Sketch 2024-06-16 13:24:56 +05:30
Manav Rathi
f69daa4608 [workers] Import public albums worker (#2158) 2024-06-16 10:19:42 +05:30
Manav Rathi
290564c973 x-client-package
Albums app is using the old axios layer which is passing "x-client-package",
will also allow that for now
2024-06-16 10:06:22 +05:30
Manav Rathi
b781f33e4b ditto 2024-06-16 09:57:44 +05:30
Manav Rathi
b8bc01561d GET
Rewritten, but referencing the existing worker imported from the dashboard
2024-06-16 09:55:49 +05:30
Manav Rathi
734cb798d3 Handle options
Rewritten, but referencing the existing worker imported from the dashboard
2024-06-16 09:27:59 +05:30
Manav Rathi
ac8ebd0ed3 Skeleton 2024-06-16 08:56:07 +05:30
Manav Rathi
fc5eb296d2 Disable default route 2024-06-16 08:39:59 +05:30
Manav Rathi
c05d8a8e44 [worker] Use tail worker for logging (#2153) 2024-06-15 22:59:50 +05:30
Manav Rathi
24845a4735 Update README 2024-06-15 22:56:32 +05:30
Manav Rathi
2b490fe131 Cleanup 2024-06-15 22:49:35 +05:30
Manav Rathi
07f0cc9342 Need to pass creds in authorization header 2024-06-15 22:35:38 +05:30
Manav Rathi
49ddd287d0 Only log interesting events 2024-06-15 20:18:10 +05:30
Manav Rathi
bffcd11100 console.log 2024-06-15 19:47:20 +05:30
Manav Rathi
25d6ebdb19 Add a check for an upcoming restriction 2024-06-15 19:42:10 +05:30
Manav Rathi
64a539adb0 Hook it up 2024-06-15 19:23:05 +05:30
Manav Rathi
3646809f06 Promise<void>
Ref: https://dev.to/krasun/pushing-cloudflare-worker-logs-to-grafana-loki-1elg
2024-06-15 19:18:39 +05:30
Manav Rathi
fb0e857514 Push the entire event (it contains the worker name too) 2024-06-15 19:16:17 +05:30
Manav Rathi
a1059c543b Fill in 2024-06-15 19:09:42 +05:30
Manav Rathi
8fe2b9cb27 The protocol 2024-06-15 18:27:44 +05:30
Manav Rathi
5e080a90e3 Skeletal tail worker 2024-06-15 17:51:46 +05:30
Vishnu Mohandas
08255b3f8a ente -> Ente (#2151) 2024-06-15 16:21:45 +05:30
vishnukvmd
f032739461 ente -> Ente 2024-06-15 16:21:10 +05:30
Manav Rathi
841da80c97 [workers] Minor cleanup, in prep for moving more of their siblings here (#2149) 2024-06-15 12:28:34 +05:30
Manav Rathi
60b1c32567 Note 2024-06-15 12:09:21 +05:30
Manav Rathi
bd6ac2c4fc Sync 2024-06-15 12:03:32 +05:30
Manav Rathi
eaccba5f22 Explicit header whitelist 2024-06-15 12:02:29 +05:30
Manav Rathi
562313b218 Tweaks 2024-06-15 11:54:26 +05:30
Manav Rathi
0650d176ee Latest yarn
Corepack will automatically install the latest one
2024-06-15 11:44:39 +05:30
Manav Rathi
6bbd944de4 Update compt date
> When you start your project, you should always set compatibility_date to the
> current date. You should occasionally update the compatibility_date field.
>
> https://developers.cloudflare.com/workers/configuration/compatibility-dates/
2024-06-15 11:41:09 +05:30
Manav Rathi
8aaad79897 yarn add --dev '@cloudflare/workers-types@latest' 2024-06-15 11:39:56 +05:30
Manav Rathi
d499549734 Use syntax recommended in docs
https://developers.cloudflare.com/workers/configuration/routing/custom-domains
2024-06-15 11:26:54 +05:30
Nikunj Kumar Nakum
db22c5bc97 Update custom-icons.json
updated coindcx icon
2024-06-15 10:51:25 +05:30
Nikunj Kumar Nakum
34f49362fd Added CoinDCX icon
Uploaded coindcx svg file
2024-06-15 10:46:49 +05:30
Manav Rathi
af21ff640d (CF's) fetch can return a promise 2024-06-15 10:03:39 +05:30
Manav Rathi
69e69c2e0f Formatting and other minor tweaks 2024-06-15 09:54:28 +05:30
Vishnu Mohandas
a0445fb4f6 v901 (#2142) 2024-06-15 00:42:56 +05:30
Prateek Sunal
8161403d84 fix(workflow/auth): use custom distributor repo for appimage 2024-06-15 00:39:51 +05:30
Prateek Sunal
0713e34aec chore(auth): bump packages 2024-06-15 00:35:46 +05:30
Prateek Sunal
b504f554b3 fix(auth): add mimetype to appimage 2024-06-15 00:35:27 +05:30
vishnukvmd
3d6af698b6 v901 2024-06-15 00:00:07 +05:30
Prateek Sunal
ff3ddb3d8d fix(auth): update deep link for linux 2024-06-14 22:52:29 +05:30
71 changed files with 919 additions and 206 deletions

View File

@@ -6,7 +6,7 @@ FEATURES
- Secure Backups
Auth provides end-to-end encrypted cloud backups so that you don't have to worry
about losing your tokens. We use the same protocols ente Photos uses to encrypt
about losing your tokens. We use the same protocols Ente Photos uses to encrypt
and preserve your data.
- Multi Device Synchronization

View File

@@ -67,6 +67,9 @@
{
"title": "Cloudflare"
},
{
"title": "CoinDCX"
},
{
"title": "ConfigCat"
},

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 500 500">
<path fill="#182954" d="m75.705 269.386 12.606 10.812a40.902 40.902 0 0 1-8.642 8.853 53.365 53.365 0 0 1-13.599 7.73 45.769 45.769 0 0 1-16.998 3.094 49.02 49.02 0 0 1-25.212-6.466A45.84 45.84 0 0 1 6.72 275.84a50.83 50.83 0 0 1-6.212-25.287 52.621 52.621 0 0 1 3.525-19.394 49.28 49.28 0 0 1 10.2-16.022 46.603 46.603 0 0 1 15.44-10.812 49.626 49.626 0 0 1 19.969-3.938 45.9 45.9 0 0 1 23.51 5.48A49.016 49.016 0 0 1 88.308 219.5l-12.744 11.244A39.368 39.368 0 0 0 64.938 220.2a27.358 27.358 0 0 0-15.296-3.933 27.636 27.636 0 0 0-16.147 4.632 30.695 30.695 0 0 0-10.478 12.508 38.957 38.957 0 0 0-3.688 16.879 36.724 36.724 0 0 0 3.684 16.442 29.719 29.719 0 0 0 10.184 11.793 27.208 27.208 0 0 0 15.44 4.358c4.608.197 9.203-.62 13.456-2.391a27.765 27.765 0 0 0 8.214-5.622l5.381-5.481M93.275 264.047a35.477 35.477 0 0 1 4.535-17.71 34.84 34.84 0 0 1 12.748-12.929 39.497 39.497 0 0 1 18.838-4.778 39.497 39.497 0 0 1 18.838 4.778 34.846 34.846 0 0 1 12.749 12.928 36.889 36.889 0 0 1 4.532 17.709 36.891 36.891 0 0 1-4.532 17.708 36.519 36.519 0 0 1-13.365 13.153 36.875 36.875 0 0 1-18.181 4.837 36.88 36.88 0 0 1-18.203-4.756 36.513 36.513 0 0 1-13.424-13.092 35.479 35.479 0 0 1-4.535-17.707v-.141zm35.979 21.224a16.949 16.949 0 0 0 10.623-3.23c2.804-2.121 5-4.93 6.375-8.151a24.848 24.848 0 0 0 2.124-9.698 24.293 24.293 0 0 0-2.124-9.697 20.265 20.265 0 0 0-6.375-8.15 19.056 19.056 0 0 0-10.623-3.233 19.057 19.057 0 0 0-10.625 3.233 20.118 20.118 0 0 0-6.231 8.009 24.296 24.296 0 0 0-2.125 9.697 24.713 24.713 0 0 0 2.125 9.839 19.985 19.985 0 0 0 6.374 8.15 16.949 16.949 0 0 0 10.624 3.231M168.905 202.628h16.856v17.71h-16.856v-17.71zm0 28.11h16.856v66.758h-16.856v-66.758zM192.416 297.495V230.88h16.147l.42 7.589a35.937 35.937 0 0 1 7.505-5.905 23.656 23.656 0 0 1 12.749-3.094 24.38 24.38 0 0 1 10.396 1.612 24.22 24.22 0 0 1 8.726 5.836 29.047 29.047 0 0 1 6.66 20.097v40.477H238.02v-40.335a13.257 13.257 0 0 0-.76-5.278 13.337 13.337 0 0 0-2.78-4.561 12.19 12.19 0 0 0-4.164-2.694 12.27 12.27 0 0 0-4.902-.82 14.974 14.974 0 0 0-6.377 1.24 14.87 14.87 0 0 0-5.236 3.82 18.046 18.046 0 0 0-4.534 12.51v36.118l-16.851.004z"/>
<path fill="#FA4A29" d="m463.25 246.618 29.754-44.007h-28.187l-15.44 24.596-15.883-24.596h-31.163l1.416 1.967-.993-.416a63.329 63.329 0 0 0-23.083-4.046 50.453 50.453 0 0 0-25.92 6.607 46.609 46.609 0 0 0-14.308 12.929 40.334 40.334 0 0 0-15.582-11.806 65.028 65.028 0 0 0-26.344-5.077h-36.686v94.727h36.544a64.026 64.026 0 0 0 26.344-5.202A41.612 41.612 0 0 0 339.3 280.63c3.87 5.299 8.846 9.709 14.59 12.928a51.44 51.44 0 0 0 25.777 6.325 55.023 55.023 0 0 0 24.646-5.34l-1.982 2.953h27.76l18.558-29.108 19.122 29.108h31.73l-36.252-50.878zm-147.452 21.624a25.772 25.772 0 0 1-8.902 5.504 25.916 25.916 0 0 1-10.376 1.523h-10.334v-50.573h10.338c3.62-.305 7.264.165 10.685 1.378a25.427 25.427 0 0 1 9.147 5.65 26.146 26.146 0 0 1 6.374 18.271 24.821 24.821 0 0 1-1.597 9.836 24.965 24.965 0 0 1-5.343 8.436l.008-.025zm101.549 6.911-12.04-11.228a38.572 38.572 0 0 1-10.197 9.149 27.09 27.09 0 0 1-13.6 2.952 25.509 25.509 0 0 1-13.314-3.372 22.838 22.838 0 0 1-8.8-9.415 29.459 29.459 0 0 1-3.118-13.63c-.091-4.623.929-9.2 2.975-13.353a23.258 23.258 0 0 1 8.642-9.415 25.653 25.653 0 0 1 13.738-3.513 24.798 24.798 0 0 1 12.748 3.23 32.061 32.061 0 0 1 9.639 8.733l12.606-12.508 18.415 26.28-17.694 26.09z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -6,7 +6,7 @@ FEATURES
- Secure Backups
ente provides end-to-end encrypted cloud backups so that you don't have to worry
about losing your tokens. We use the same protocols ente Photos uses to encrypt
about losing your tokens. We use the same protocols Ente Photos uses to encrypt
and preserve your data.
- Multi Device Synchronization

View File

@@ -27,3 +27,6 @@ include:
- libffi.so.8
- libtiff.so.5
- libjpeg.so.8
supported_mime_type:
- x-scheme-handler/enteauth

View File

@@ -31,4 +31,4 @@ categories:
startup_notify: false
supported_mime_type:
- x-scheme-handler/ente
- x-scheme-handler/enteauth

View File

@@ -28,4 +28,4 @@ categories:
startup_notify: false
supported_mime_type:
- x-scheme-handler/ente
- x-scheme-handler/enteauth

View File

@@ -45,10 +45,10 @@ packages:
dependency: "direct main"
description:
name: archive
sha256: "0763b45fa9294197a2885c8567927e2830ade852e5c896fd4ab7e0e348d0f373"
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
url: "https://pub.dev"
source: hosted
version: "3.5.0"
version: "3.6.1"
args:
dependency: transitive
description:
@@ -117,10 +117,10 @@ packages:
dependency: transitive
description:
name: build_daemon
sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
url: "https://pub.dev"
source: hosted
version: "4.0.1"
version: "4.0.2"
build_resolvers:
dependency: transitive
description:
@@ -133,18 +133,18 @@ packages:
dependency: "direct dev"
description:
name: build_runner
sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22"
sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7"
url: "https://pub.dev"
source: hosted
version: "2.4.9"
version: "2.4.11"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799"
sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe
url: "https://pub.dev"
source: hosted
version: "7.3.0"
version: "7.3.1"
built_collection:
dependency: transitive
description:
@@ -415,10 +415,10 @@ packages:
dependency: "direct main"
description:
name: file_saver
sha256: bdebc720e17b3e01aba59da69b6d47020a7e5ba7d5c75bd9194f9618d5f16ef4
sha256: d375b351e3331663abbaf99747abd72f159260c58fbbdbca9f926f02c01bdc48
url: "https://pub.dev"
source: hosted
version: "0.2.12"
version: "0.2.13"
fixnum:
dependency: "direct main"
description:
@@ -444,10 +444,10 @@ packages:
dependency: "direct main"
description:
name: flutter_bloc
sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
url: "https://pub.dev"
source: hosted
version: "8.1.5"
version: "8.1.6"
flutter_context_menu:
dependency: "direct main"
description:
@@ -586,18 +586,18 @@ packages:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f"
sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e
url: "https://pub.dev"
source: hosted
version: "2.0.19"
version: "2.0.20"
flutter_secure_storage:
dependency: "direct main"
description:
name: flutter_secure_storage
sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685
sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
url: "https://pub.dev"
source: hosted
version: "9.0.0"
version: "9.2.2"
flutter_secure_storage_linux:
dependency: "direct overridden"
description:
@@ -611,34 +611,34 @@ packages:
dependency: transitive
description:
name: flutter_secure_storage_macos
sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c
sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.1.2"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e"
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.2"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20"
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.2.1"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108"
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
url: "https://pub.dev"
source: hosted
version: "3.0.0"
version: "3.1.2"
flutter_slidable:
dependency: "direct main"
description:
@@ -685,10 +685,10 @@ packages:
dependency: "direct main"
description:
name: fluttertoast
sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66"
sha256: "7eae679e596a44fdf761853a706f74979f8dd3cd92cf4e23cae161fda091b847"
url: "https://pub.dev"
source: hosted
version: "8.2.5"
version: "8.2.6"
freezed_annotation:
dependency: transitive
description:
@@ -725,10 +725,10 @@ packages:
dependency: "direct main"
description:
name: gradient_borders
sha256: "69eeaff519d145a4c6c213ada1abae386bcc8981a4970d923e478ce7ba19e309"
sha256: b1cd969552c83f458ff755aa68e13a0327d09f06c3f42f471b423b01427f21f8
url: "https://pub.dev"
source: hosted
version: "1.0.0"
version: "1.0.1"
graphs:
dependency: transitive
description:
@@ -757,10 +757,10 @@ packages:
dependency: transitive
description:
name: hashlib_codecs
sha256: "49e2a471f74b15f1854263e58c2ac11f2b631b5b12c836f9708a35397d36d626"
sha256: a1c7b5d89ff29e81fd8e8c0b35966db4c935e149fc4ebe1ebf71e358c15863ab
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.4.0"
hex:
dependency: transitive
description:
@@ -805,10 +805,10 @@ packages:
dependency: transitive
description:
name: image
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8"
url: "https://pub.dev"
source: hosted
version: "4.1.7"
version: "4.2.0"
intl:
dependency: "direct main"
description:
@@ -893,18 +893,18 @@ packages:
dependency: "direct main"
description:
name: local_auth_android
sha256: e0e5b1ea247c5a0951c13a7ee13dc1beae69750e6a2e1910d1ed6a3cd4d56943
sha256: "48dfb2d954da8ef6a77adfc93a29998f7729e9308eaa817e91dea4500317b2c8"
url: "https://pub.dev"
source: hosted
version: "1.0.38"
version: "1.0.39"
local_auth_darwin:
dependency: "direct main"
description:
name: local_auth_darwin
sha256: "33381a15b0de2279523eca694089393bb146baebdce72a404555d03174ebc1e9"
sha256: e424ebf90d5233452be146d4a7da4bcd7a70278b67791592f3fde1bda8eef9e2
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.1"
local_auth_platform_interface:
dependency: transitive
description:
@@ -973,10 +973,10 @@ packages:
dependency: "direct dev"
description:
name: mocktail
sha256: c4b5007d91ca4f67256e720cb1b6d704e79a510183a12fa551021f652577dce6
sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
version: "1.0.4"
modal_bottom_sheet:
dependency: "direct main"
description:
@@ -1085,18 +1085,18 @@ packages:
dependency: transitive
description:
name: path_provider_android
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514"
url: "https://pub.dev"
source: hosted
version: "2.2.4"
version: "2.2.5"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.4.0"
path_provider_linux:
dependency: transitive
description:
@@ -1141,10 +1141,10 @@ packages:
dependency: transitive
description:
name: platform
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
version: "3.1.5"
plugin_platform_interface:
dependency: transitive
description:
@@ -1157,10 +1157,10 @@ packages:
dependency: "direct main"
description:
name: pointycastle
sha256: "79fbafed02cfdbe85ef3fd06c7f4bc2cbcba0177e61b765264853d4253b21744"
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev"
source: hosted
version: "3.9.0"
version: "3.9.1"
pool:
dependency: transitive
description:
@@ -1205,10 +1205,10 @@ packages:
dependency: transitive
description:
name: pubspec_parse
sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
url: "https://pub.dev"
source: hosted
version: "1.2.3"
version: "1.3.0"
qr:
dependency: transitive
description:
@@ -1245,18 +1245,18 @@ packages:
dependency: "direct main"
description:
name: sentry
sha256: e572d33a3ff1d69549f33ee828a8ff514047d43ca8eea4ab093d72461205aa3e
sha256: "57514bc72d441ffdc463f498d6886aa586a2494fa467a1eb9d649c28010d7ee3"
url: "https://pub.dev"
source: hosted
version: "7.20.1"
version: "7.20.2"
sentry_flutter:
dependency: "direct main"
description:
name: sentry_flutter
sha256: ac8cf6bb849f3560353ae33672e17b2713809a4e8de0d3cf372e9e9c42013757
sha256: "9723d58470ca43a360681ddd26abb71ca7b815f706bc8d3747afd054cf639ded"
url: "https://pub.dev"
source: hosted
version: "7.20.1"
version: "7.20.2"
share_plus:
dependency: "direct main"
description:
@@ -1285,18 +1285,18 @@ packages:
dependency: transitive
description:
name: shared_preferences_android
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
version: "2.2.3"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
url: "https://pub.dev"
source: hosted
version: "2.3.5"
version: "2.4.0"
shared_preferences_linux:
dependency: transitive
description:
@@ -1341,10 +1341,10 @@ packages:
dependency: transitive
description:
name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "2.0.0"
shortid:
dependency: transitive
description:
@@ -1370,10 +1370,10 @@ packages:
dependency: transitive
description:
name: sodium_libs
sha256: f7f6719b7ab3e8512ce7a5ecd7bc8d865482431cdd5a07a46b55b13c152b54e1
sha256: "441444f6f433032bae3444c2ef5ed2cf5bc0def77f104abdff20aedcf79a7c7a"
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
version: "2.2.1+5"
source_gen:
dependency: transitive
description:
@@ -1411,10 +1411,10 @@ packages:
description:
path: sqflite
ref: HEAD
resolved-ref: f281785e12e8b1abf2f9d41a587fc83d810724cf
resolved-ref: "3309d399dd7d695bbfa7c05f643bb16765cef4ee"
url: "https://github.com/tekartik/sqflite"
source: git
version: "2.3.3"
version: "2.3.3+1"
sqflite_common:
dependency: transitive
description:
@@ -1435,18 +1435,18 @@ packages:
dependency: "direct main"
description:
name: sqlite3
sha256: "1abbeb84bf2b1a10e5e1138c913123c8aa9d83cd64e5f9a0dd847b3c83063202"
sha256: b384f598b813b347c5a7e5ffad82cbaff1bec3d1561af267041e66f6f0899295
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.3"
sqlite3_flutter_libs:
dependency: "direct main"
description:
name: sqlite3_flutter_libs
sha256: fb2a106a2ea6042fe57de2c47074cc31539a941819c91e105b864744605da3f5
sha256: "9f89a7e7dc36eac2035808427eba1c3fbd79e59c3a22093d8dace6d36b1fe89e"
url: "https://pub.dev"
source: hosted
version: "0.5.21"
version: "0.5.23"
stack_trace:
dependency: transitive
description:
@@ -1547,10 +1547,10 @@ packages:
dependency: "direct main"
description:
name: tray_manager
sha256: e0ac9a88b2700f366b8629b97e8663b6ef450a2f169560a685dc167bfe9c9c29
sha256: c9a63fd88bd3546287a7eb8ccc978d707eef82c775397af17dda3a4f4c039e64
url: "https://pub.dev"
source: hosted
version: "0.2.2"
version: "0.2.3"
tuple:
dependency: "direct main"
description:
@@ -1579,26 +1579,26 @@ packages:
dependency: "direct main"
description:
name: url_launcher
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
url: "https://pub.dev"
source: hosted
version: "6.2.6"
version: "6.3.0"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775"
sha256: ceb2625f0c24ade6ef6778d1de0b2e44f2db71fded235eb52295247feba8c5cf
url: "https://pub.dev"
source: hosted
version: "6.3.1"
version: "6.3.3"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89"
url: "https://pub.dev"
source: hosted
version: "6.2.5"
version: "6.3.0"
url_launcher_linux:
dependency: transitive
description:
@@ -1611,10 +1611,10 @@ packages:
dependency: transitive
description:
name: url_launcher_macos
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.2.0"
url_launcher_platform_interface:
dependency: transitive
description:
@@ -1703,22 +1703,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.1"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "24301d8c293ce6fe327ffe6f59d8fd8834735f0ec36e4fd383ec7ff8a64aa078"
url: "https://pub.dev"
source: hosted
version: "0.1.5"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
sha256: a2d56211ee4d35d9b344d9d4ce60f362e4f5d1aafb988302906bd732bc731276
url: "https://pub.dev"
source: hosted
version: "2.4.5"
version: "3.0.0"
win32:
dependency: "direct main"
description:
name: win32
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev"
source: hosted
version: "5.5.0"
version: "5.5.1"
win32_registry:
dependency: transitive
description:
@@ -1768,5 +1776,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.3.0 <4.0.0"
flutter: ">=3.19.0"
dart: ">=3.4.0 <4.0.0"
flutter: ">=3.22.0"

View File

@@ -1,6 +1,6 @@
# CHANGELOG
## v1.7.1 (Unreleased)
## v1.7.1
- Support for passkeys as a second factor authentication mechanism.
- Remember the window size across app restarts.

View File

@@ -1,6 +1,6 @@
{
"name": "ente",
"version": "1.7.1-rc",
"version": "1.7.1",
"private": true,
"description": "Desktop client for Ente Photos",
"repository": "github:ente-io/photos-desktop",

View File

@@ -20,8 +20,12 @@ start it, then you might need to install the VC++ runtime from Microsoft.
This is what the error looks like:
<div style="border: 1px solid black">
![Error when VC++ runtime is not installed](windows-vc.png){width=500px}
</div>
You can install the Microsoft VC++ redistributable runtime from here:<br/>
https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version

View File

@@ -1,3 +1,4 @@
{
"tabWidth": 4
"tabWidth": 4,
"proseWrap": "always"
}

View File

@@ -1,23 +1,26 @@
# Cloudflare Workers
Source code for our [Cloudflare
Workers](https://developers.cloudflare.com/workers/).
Source code for our
[Cloudflare Workers](https://developers.cloudflare.com/workers/).
Each worker is a self contained directory with its each `package.json`.
## Deploying
* Switch to a worker directory, e.g. `cd github-discord-notifier`.
- Switch to a worker directory, e.g. `cd github-discord-notifier`.
* Install dependencies (if needed) with `yarn`
- Install dependencies (if needed) with `yarn`
* Login into wrangler (if needed) using `yarn wrangler login`
> If you have previously deployed, then you will have an old `yarn.lock`. In
> this case it is safe to delete and recreate using `rm yarn.lock && yarn`.
* Deploy! `yarn wrangler deploy`
- Login into wrangler (if needed) using `yarn wrangler login`
- Deploy! `yarn wrangler deploy`
Wrangler is the CLI provided by Cloudflare to manage workers. Apart from
deploying, it also allows us to stream logs from running workers by using `yarn
wrangler tail`.
deploying, it also allows us to stream logs from running workers by using
`yarn wrangler tail`.
## Creating a new worker
@@ -30,3 +33,12 @@ To import an existing worker from the Cloudflare dashboard, use
```sh
npm create cloudflare@2 existing-worker-name -- --type pre-existing --existing-script existing-worker-name
```
## Logging
Attach the tail worker to your worker by adding
tail_consumers = [{ service = "tail" }]
in its `wrangler.toml`. Then any `console.(log|warn|error)` statements and
uncaught exceptions in your worker will be logged to Grafana.

View File

@@ -2,8 +2,9 @@
"name": "cast-albums",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240314.0",
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
}
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -1,50 +1,69 @@
/** Proxy file and thumbnail requests from the cast web app */
/** Proxy file and thumbnail requests for the cast web app. */
export default {
async fetch(request: Request) {
switch (request.method) {
case "GET":
return handleGET(request);
case "OPTIONS":
return handleOPTIONS(request);
case "GET":
return handleGET(request);
default:
throw new Error(
`HTTP 405 Method Not Allowed: ${request.method}`
);
console.log(`Unsupported HTTP method ${request.method}`);
return new Response(null, { status: 405 });
}
},
} satisfies ExportedHandler;
const handleOPTIONS = (request: Request) => {
const origin = request.headers.get("Origin");
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
return new Response("", {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Max-Age": "86400",
"Access-Control-Allow-Headers": "X-Cast-Access-Token",
},
});
};
const isAllowedOrigin = (origin: string | null) => {
const allowed = ["cast.ente.io", "cast.ente.sh", "localhost"];
if (!origin) return false;
try {
const url = new URL(origin);
return allowed.includes(url.hostname);
} catch {
// origin is likely an invalid URL
return false;
}
};
const handleGET = async (request: Request) => {
const url = new URL(request.url);
const urlParams = new URLSearchParams(url.search);
const token =
request.headers.get("X-Cast-Access-Token") ??
urlParams.get("castToken");
const fileID = urlParams.get("fileID");
const fileID = url.searchParams.get("fileID");
if (!fileID) return new Response(null, { status: 400 });
let castToken = request.headers.get("X-Cast-Access-Token");
if (!castToken) {
console.warn("Using deprecated castToken query param");
castToken = url.searchParams.get("castToken");
}
if (!castToken) {
console.error("No cast token provided");
return new Response(null, { status: 400 });
}
const pathname = url.pathname;
const params = new URLSearchParams({ castToken });
let response = await fetch(
`https://api.ente.io/cast/files${pathname}${fileID}?castToken=${token}`
`https://api.ente.io/cast/files${pathname}${fileID}?${params.toString()}`
);
response = new Response(response.body, response);
response.headers.set("Access-Control-Allow-Origin", "*");
return response;
};
const handleOPTIONS = (request: Request) => {
let corsHeaders: Record<string, string> = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,OPTIONS",
"Access-Control-Max-Age": "86400",
};
const acrh = request.headers.get("Access-Control-Request-Headers");
if (acrh) {
corsHeaders["Access-Control-Allow-Headers"] = acrh;
}
return new Response("", { headers: corsHeaders });
};

View File

@@ -1 +1 @@
{ "extends": "../tsconfig.base.json", "include": ["src/**/*.ts"] }
{ "extends": "../tsconfig.base.json", "include": ["src"] }

View File

@@ -1,8 +1,11 @@
name = "cast-albums"
main = "src/index.ts"
compatibility_date = "2024-03-14"
compatibility_date = "2024-06-14"
[[routes]]
pattern = "cast-albums.ente.io"
zone_name = "ente.io"
custom_domain = true
routes = [
{ pattern = "cast-albums.ente.io", custom_domain = true }
]
tail_consumers = [
{ service = "tail" }
]

View File

@@ -0,0 +1,10 @@
{
"name": "files",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -0,0 +1,101 @@
/** Proxy requests for files. */
export default {
async fetch(request: Request) {
switch (request.method) {
case "OPTIONS":
return handleOPTIONS(request);
case "GET":
return handleGET(request);
default:
console.log(`Unsupported HTTP method ${request.method}`);
return new Response(null, { status: 405 });
}
},
} satisfies ExportedHandler;
const handleOPTIONS = (request: Request) => {
const origin = request.headers.get("Origin");
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
const headers = request.headers.get("Access-Control-Request-Headers");
if (!areAllowedHeaders(headers))
console.warn("Unknown header in list", headers);
return new Response("", {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Max-Age": "86400",
// "Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
"Access-Control-Allow-Headers": "*",
},
});
};
const isAllowedOrigin = (origin: string | null) => {
const desktopApp = "ente://app";
const allowedHostnames = [
"web.ente.io",
"photos.ente.io",
"photos.ente.sh",
"localhost",
];
if (!origin) return false;
try {
const url = new URL(origin);
return origin == desktopApp || allowedHostnames.includes(url.hostname);
} catch {
// origin is likely an invalid URL
return false;
}
};
const areAllowedHeaders = (headers: string | null) => {
const allowed = ["x-auth-token", "x-client-package"];
if (!headers) return true;
for (const header of headers.split(",")) {
if (!allowed.includes(header.trim().toLowerCase())) return false;
}
return true;
};
const handleGET = async (request: Request) => {
const url = new URL(request.url);
// Random bots keep trying to pentest causing noise in the logs. If the
// request doesn't have a fileID, we can just safely ignore it thereafter.
const fileID = url.searchParams.get("fileID");
if (!fileID) return new Response(null, { status: 400 });
let token = request.headers.get("X-Auth-Token");
if (!token) {
console.warn("Using deprecated token query param");
token = url.searchParams.get("token");
}
if (!token) {
console.error("No token provided");
// return new Response(null, { status: 400 });
}
// We forward the auth token as a query parameter to museum. This is so that
// it does not get preserved when museum does a redirect to the presigned S3
// URL that serves the actual thumbnail.
//
// See: [Note: Passing credentials for self-hosted file fetches]
const params = new URLSearchParams();
if (token) params.set("token", token);
let response = await fetch(
`https://api.ente.io/files/download/${fileID}?${params.toString()}`,
{
headers: {
"User-Agent": request.headers.get("User-Agent") ?? "",
},
}
);
response = new Response(response.body, response);
response.headers.set("Access-Control-Allow-Origin", "*");
return response;
};

View File

@@ -0,0 +1 @@
{ "extends": "../tsconfig.base.json", "include": ["src"] }

View File

@@ -0,0 +1,11 @@
name = "files"
main = "src/index.ts"
compatibility_date = "2024-06-14"
routes = [
{ pattern = "files.ente.io", custom_domain = true }
]
tail_consumers = [
{ service = "tail" }
]

View File

@@ -2,8 +2,9 @@
"name": "github-discord-notifier",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240314.0",
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
}
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -2,7 +2,7 @@
* Forward notifications from GitHub to Discord.
*
* This worker receives webhooks from GitHub, filters out the ones we don't
* need, and forwards them to a Discord webhook.
* need, and forwards the rest to a Discord webhook.
*/
export default {
async fetch(request: Request, env: Env) {
@@ -33,13 +33,13 @@ const handleRequest = async (request: Request, discordWebhookURL: string) => {
// doesn't work for get silently ignored (Discord responds with a 204).
// https://github.com/discord/discord-api-docs/issues/6203#issuecomment-1608151265
let response = await fetch(`${discordWebhookURL}/github`, {
const response = await fetch(`${discordWebhookURL}/github`, {
method: request.method,
headers: request.headers,
body: requestBody,
});
if (response.status === 429) {
if (response.status == 429) {
// Sometimes Discord starts returning 429 Rate Limited responses when we
// try to invoke the webhook.
//
@@ -79,7 +79,7 @@ const handleRequest = async (request: Request, discordWebhookURL: string) => {
const action = requestJSON["action"];
if (activityURL && ["created", "opened"].includes(action)) {
response = await fetch(discordWebhookURL, {
return fetch(discordWebhookURL, {
method: request.method,
headers: request.headers,
body: JSON.stringify({
@@ -89,12 +89,5 @@ const handleRequest = async (request: Request, discordWebhookURL: string) => {
}
}
const responseBody = await response.text();
const newResponse = new Response(responseBody, {
status: response.status,
statusText: response.statusText,
headers: response.headers,
});
return newResponse;
return response;
};

View File

@@ -1 +1 @@
{ "extends": "../tsconfig.base.json", "include": ["src/**/*.ts"] }
{ "extends": "../tsconfig.base.json", "include": ["src"] }

View File

@@ -1,6 +1,6 @@
name = "github-discord-notifier"
main = "src/index.ts"
compatibility_date = "2024-03-14"
compatibility_date = "2024-06-14"
[vars]
# Added as a secret via the Cloudflare dashboard

View File

@@ -0,0 +1,10 @@
{
"name": "health-check",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -0,0 +1,48 @@
/** Ping api.ente.io every minute and yell if it doesn't pong. */
export default {
async scheduled(_, env: Env, ctx: ExecutionContext) {
ctx.waitUntil(ping(env, ctx));
},
} satisfies ExportedHandler<Env>;
interface Env {
NOTIFY_URL: string;
CHAT_ID: string;
}
const ping = async (env: Env, ctx: ExecutionContext) => {
const notify = async (msg: string) =>
sendMessage(`${msg} on ${Date()}`, env);
try {
let timeout = setTimeout(() => {
ctx.waitUntil(notify("Ping timed out"));
}, 5000);
const res = await fetch("https://api.ente.io/ping", {
headers: {
"User-Agent": "health-check",
},
});
clearTimeout(timeout);
if (!res.ok) await notify(`Ping failed (HTTP ${res.status})`);
} catch (e) {
await notify(`Ping failed (${e instanceof Error ? e.message : e})`);
}
};
const sendMessage = async (message: string, env: Env) => {
console.log(message);
const res = await fetch(env.NOTIFY_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
chat_id: parseInt(env.CHAT_ID),
parse_mode: "html",
text: message,
}),
});
if (!res.ok) throw new Error(`Failed to sendMessage (HTTP ${res.status})`);
};

View File

@@ -0,0 +1 @@
{ "extends": "../tsconfig.base.json", "include": ["src"] }

View File

@@ -0,0 +1,17 @@
name = "health-check"
main = "src/index.ts"
compatibility_date = "2024-06-14"
# Disable the default route, this worker does not handle fetch.
workers_dev = false
tail_consumers = [{ service = "tail" }]
[vars]
# Added as a secret via the Cloudflare dashboard
# NOTIFY_URL = ""
# CHAT_ID = ""
[triggers]
# Every minute
crons = [ "*/1 * * * *" ]

View File

@@ -0,0 +1,10 @@
{
"name": "public-albums",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -0,0 +1,98 @@
/** Proxy requests for files and thumbnails in public albums. */
export default {
async fetch(request: Request) {
switch (request.method) {
case "OPTIONS":
return handleOPTIONS(request);
case "GET":
return handleGET(request);
default:
console.log(`Unsupported HTTP method ${request.method}`);
return new Response(null, { status: 405 });
}
},
} satisfies ExportedHandler;
const handleOPTIONS = (request: Request) => {
const origin = request.headers.get("Origin");
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
const headers = request.headers.get("Access-Control-Request-Headers");
if (!areAllowedHeaders(headers))
console.warn("Unknown header in list", headers);
return new Response("", {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Max-Age": "86400",
// "Access-Control-Allow-Headers": "X-Auth-Access-Token, X-Auth-Access-Token-JWT",
// "Access-Control-Allow-Headers": "X-Auth-Access-Token, X-Auth-Access-Token-JWT, x-client-package",
"Access-Control-Allow-Headers": "*",
},
});
};
const isAllowedOrigin = (origin: string | null) => {
const allowed = ["albums.ente.io", "albums.ente.sh", "localhost"];
if (!origin) return false;
try {
const url = new URL(origin);
return allowed.includes(url.hostname);
} catch {
// origin is likely an invalid URL
return false;
}
};
const areAllowedHeaders = (headers: string | null) => {
// TODO(MR): Stop sending "x-client-package"
const allowed = [
"x-auth-access-token",
"x-auth-access-token-jwt",
"x-client-package",
];
if (!headers) return true;
for (const header of headers.split(",")) {
if (!allowed.includes(header.trim().toLowerCase())) return false;
}
return true;
};
const handleGET = async (request: Request) => {
const url = new URL(request.url);
const fileID = url.searchParams.get("fileID");
if (!fileID) return new Response(null, { status: 400 });
let accessToken = request.headers.get("X-Auth-Access-Token");
if (accessToken === undefined) {
console.warn("Using deprecated accessToken query param");
accessToken = url.searchParams.get("accessToken");
}
if (!accessToken) {
console.error("No accessToken provided");
// return new Response(null, { status: 400 });
}
let accessTokenJWT = request.headers.get("X-Auth-Access-Token-JWT");
if (accessTokenJWT === undefined) {
console.warn("Using deprecated accessTokenJWT query param");
accessTokenJWT = url.searchParams.get("accessTokenJWT");
}
const pathname = url.pathname;
const params = new URLSearchParams();
if (accessToken) params.set("accessToken", accessToken);
if (accessTokenJWT) params.set("accessTokenJWT", accessTokenJWT);
let response = await fetch(
`https://api.ente.io/public-collection/files${pathname}${fileID}?${params.toString()}`
);
response = new Response(response.body, response);
response.headers.set("Access-Control-Allow-Origin", "*");
return response;
};

View File

@@ -0,0 +1 @@
{ "extends": "../tsconfig.base.json", "include": ["src"] }

View File

@@ -0,0 +1,11 @@
name = "public-albums"
main = "src/index.ts"
compatibility_date = "2024-06-14"
routes = [
{ pattern = "public-albums.ente.io", custom_domain = true }
]
tail_consumers = [
{ service = "tail" }
]

View File

@@ -0,0 +1,10 @@
{
"name": "tail",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -0,0 +1,72 @@
/**
* A tail worker that forwards all `console.log` (and siblings) to Loki.
*
* https://developers.cloudflare.com/workers/observability/logging/tail-workers/
*/
export default {
async tail(events: TraceItem[], env: Env) {
// If the tail worker itself throws an exception (it shouldn't, unless
// Loki is down), we don't catch it so that it counts as an "error" in
// the worker stats.
await handleTail(events, env);
},
} satisfies ExportedHandler<Env>;
interface Env {
/** The URL of the Loki instance to push logs to. */
LOKI_PUSH_URL: string;
/**
* The value of the "Basic" authorization.
*
* [Note: HTTP basic authorization in worker fetch]
*
* Usually a Loki push URL is specified with the credentials inline, say
* `http://user:pass@loki/path`. However, I cannot get that to work with the
* `fetch` inside a Cloudflare worker. Instead, the credentials need to be
* separately provided as the Authorization header of the form:
*
* Authorization: Basic ${btoa(user:pass)}
*
* The LOKI_AUTH secret is the "${btoa(user:pass)}" value.
*/
LOKI_AUTH: string;
}
const handleTail = async (events: TraceItem[], env: Env) => {
for (const event of events.filter(hasLogOrException))
await pushLogLine(Date.now(), JSON.stringify(event), env);
};
/** Return true if the {@link event} has at least one log or exception. */
const hasLogOrException = (event: TraceItem) =>
event.logs.length ?? event.exceptions.length;
/**
* Send a log entry to (Grafana) Loki
*
* For more details about the protocol, see
* https://grafana.com/docs/loki/latest/reference/loki-http-api/#ingest-logs
*
* @param timestampMs Unix epoch (in milliseconds) when the event occurred.
*
* @param logLine The message to log.
*
* @param env The worker environment; we need it for the Loki URL and
* credentials.
*/
const pushLogLine = async (timestampMs: number, logLine: string, env: Env) =>
await fetch(env.LOKI_PUSH_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Basic ${env.LOKI_AUTH}`,
},
body: JSON.stringify({
streams: [
{
stream: { job: "worker" },
values: [[`${timestampMs * 1e6}`, logLine]],
},
],
}),
});

View File

@@ -0,0 +1 @@
{ "extends": "../tsconfig.base.json", "include": ["src"] }

View File

@@ -0,0 +1,11 @@
name = "tail"
main = "src/index.ts"
compatibility_date = "2024-06-14"
# Disable the default route, this worker does not handle fetch.
workers_dev = false
[vars]
# Added as a secret via the Cloudflare dashboard
# LOKI_PUSH_URL = "https://${loki_base_url}>/loki/api/v1/push"
# LOKI_AUTH = "${btoa(user:pass)}"

View File

@@ -0,0 +1,10 @@
{
"name": "thumbnails",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -0,0 +1,89 @@
/** Proxy requests for thumbnails. */
export default {
async fetch(request: Request) {
switch (request.method) {
case "OPTIONS":
return handleOPTIONS(request);
case "GET":
return handleGET(request);
default:
console.log(`Unsupported HTTP method ${request.method}`);
return new Response(null, { status: 405 });
}
},
} satisfies ExportedHandler;
const handleOPTIONS = (request: Request) => {
const origin = request.headers.get("Origin");
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
const headers = request.headers.get("Access-Control-Request-Headers");
if (!areAllowedHeaders(headers))
console.warn("Unknown header in list", headers);
return new Response("", {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Max-Age": "86400",
// "Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
"Access-Control-Allow-Headers": "*",
},
});
};
const isAllowedOrigin = (origin: string | null) => {
const desktopApp = "ente://app";
const allowedHostnames = [
"web.ente.io",
"photos.ente.io",
"photos.ente.sh",
"localhost",
];
if (!origin) return false;
try {
const url = new URL(origin);
return origin == desktopApp || allowedHostnames.includes(url.hostname);
} catch {
// origin is likely an invalid URL
return false;
}
};
const areAllowedHeaders = (headers: string | null) => {
const allowed = ["x-auth-token", "x-client-package"];
if (!headers) return true;
for (const header of headers.split(",")) {
if (!allowed.includes(header.trim().toLowerCase())) return false;
}
return true;
};
const handleGET = async (request: Request) => {
const url = new URL(request.url);
const fileID = url.searchParams.get("fileID");
if (!fileID) return new Response(null, { status: 400 });
let token = request.headers.get("X-Auth-Token");
if (!token) {
console.warn("Using deprecated token query param");
token = url.searchParams.get("token");
}
if (!token) {
console.error("No token provided");
// return new Response(null, { status: 400 });
}
const params = new URLSearchParams();
if (token) params.set("token", token);
let response = await fetch(
`https://api.ente.io/files/preview/${fileID}?${params.toString()}`
);
response = new Response(response.body, response);
response.headers.set("Access-Control-Allow-Origin", "*");
return response;
};

View File

@@ -0,0 +1 @@
{ "extends": "../tsconfig.base.json", "include": ["src"] }

View File

@@ -0,0 +1,11 @@
name = "thumbnails"
main = "src/index.ts"
compatibility_date = "2024-06-14"
routes = [
{ pattern = "thumbnails.ente.io", custom_domain = true }
]
tail_consumers = [
{ service = "tail" }
]

View File

@@ -3,30 +3,30 @@
/* TSConfig docs: https://aka.ms/tsconfig.json */
"compilerOptions": {
/* tsc is used for by us for type checking, not compilation (the
Cloudflare workers runtime natively supports TypeScript) */
Cloudflare workers runtime natively supports TypeScript). */
"noEmit": true,
/* The Workers runtime supports the latest and greatest */
/* The Workers runtime supports the latest and greatest. */
/* https://developers.cloudflare.com/workers/reference/languages/#javascript--typescript */
"lib": ["esnext"],
"target": "esnext",
"module": "esnext",
/* Types that are implicitly available */
/* Types that are implicitly available. */
/* https://www.npmjs.com/package/@cloudflare/workers-types */
"types": ["@cloudflare/workers-types"],
/* Tell TypeScript how to lookup the file for a given import */
/* Tell TypeScript how to lookup the file for a given import. */
"moduleResolution": "node",
/* Speed things up by not type checking `node_modules` */
/* Speed things up by not type checking `node_modules`. */
"skipLibCheck": true,
/* Require the `type` modifier when importing types */
/* Require the `type` modifier when importing types. */
"verbatimModuleSyntax": true,
/* Enable importing .json files */
/* Enable importing .json files. */
"resolveJsonModule": true,
/* strict and then some */
/* strict, and then some. */
"strict": true,
"noImplicitReturns": true,
"noUnusedParameters": true,

View File

@@ -0,0 +1,10 @@
{
"name": "uploader",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -0,0 +1,123 @@
/**
* Proxy file uploads.
*
* See: https://ente.io/blog/tech/making-uploads-faster/
*/
export default {
async fetch(request: Request) {
switch (request.method) {
case "OPTIONS":
return handleOPTIONS(request);
case "POST":
return handlePOSTOrPUT(request);
case "PUT":
return handlePOSTOrPUT(request);
default:
console.log(`Unsupported HTTP method ${request.method}`);
return new Response(null, { status: 405 });
}
},
} satisfies ExportedHandler;
const handleOPTIONS = (request: Request) => {
const origin = request.headers.get("Origin");
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
const headers = request.headers.get("Access-Control-Request-Headers");
if (!areAllowedHeaders(headers))
console.warn("Unknown header in list", headers);
return new Response("", {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, PUT, OPTIONS",
"Access-Control-Max-Age": "86400",
// "Access-Control-Allow-Headers": "Content-Type", "UPLOAD-URL, X-Client-Package",
"Access-Control-Allow-Headers": "*",
"Access-Control-Expose-Headers": "X-Request-Id, CF-Ray",
},
});
};
const isAllowedOrigin = (origin: string | null) => {
const desktopApp = "ente://app";
const allowedHostnames = [
"web.ente.io",
"photos.ente.io",
"photos.ente.sh",
"localhost",
];
if (!origin) return false;
try {
const url = new URL(origin);
return origin == desktopApp || allowedHostnames.includes(url.hostname);
} catch {
// origin is likely an invalid URL
return false;
}
};
const areAllowedHeaders = (headers: string | null) => {
const allowed = ["Content-Type", "UPLOAD-URL", "X-Client-Package"];
if (!headers) return true;
for (const header of headers.split(",")) {
if (!allowed.includes(header.trim().toLowerCase())) return false;
}
return true;
};
const handlePOSTOrPUT = async (request: Request) => {
const url = new URL(request.url);
const uploadURL = request.headers.get("UPLOAD-URL");
if (!uploadURL) {
console.error("No uploadURL provided");
return new Response(null, { status: 400 });
}
let response: Response;
switch (url.pathname) {
case "/file-upload":
response = await fetch(uploadURL, {
method: request.method,
body: request.body,
});
break;
case "/multipart-upload":
response = await fetch(uploadURL, {
method: request.method,
body: request.body,
});
if (response.ok) {
const etag = response.headers.get("etag");
if (etag === null) {
console.log("No etag in response", response);
response = new Response(null, { status: 500 });
} else {
response = new Response(JSON.stringify({ etag }));
}
}
break;
case "/multipart-complete":
response = await fetch(uploadURL, {
method: request.method,
body: request.body,
headers: {
"Content-Type": "text/xml",
},
});
break;
default:
response = new Response(null, { status: 404 });
break;
}
response = new Response(response.body, response);
response.headers.set("Access-Control-Allow-Origin", "*");
response.headers.set(
"Access-Control-Expose-Headers",
"X-Request-Id, CF-Ray"
);
return response;
};

View File

@@ -0,0 +1 @@
{ "extends": "../tsconfig.base.json", "include": ["src"] }

View File

@@ -0,0 +1,7 @@
name = "uploader"
main = "src/index.ts"
compatibility_date = "2024-06-14"
routes = [{ pattern = "uploader.ente.io", custom_domain = true }]
tail_consumers = [{ service = "tail" }]

View File

@@ -1,5 +1,5 @@
<resources>
<string name="app_name">ente Photos</string>
<string name="app_name">Ente Photos</string>
<string name="backup">Backup</string>
<string name="asset_statements" translatable="false">
[{

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -1 +1 @@
ente Photos
Ente Photos

View File

@@ -12,7 +12,7 @@ description: ente photos application
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.9.0+700
version: 0.9.1+901
publish_to: none
environment:

View File

@@ -50,7 +50,7 @@ const (
SubscriptionEndedEmailTemplate = "subscription_ended.html"
// Subject for `SubscriptionEndedEmailTemplate`.
SubscriptionEndedEmailSubject = "Your subscription to ente Photos has ended"
SubscriptionEndedEmailSubject = "Your subscription to Ente Photos has ended"
)
// PaymentProvider represents the payment provider via which a purchase was made

View File

@@ -206,7 +206,7 @@
style="font-family: inherit; text-align: inherit">
<span
style="font-family: helvetica, sans-serif">Your subscription to
ente Photos has ended. Thank you for trying out ente.</span>
Ente Photos has ended. Thank you for trying out ente.</span>
</div>
<div
style="font-family: inherit; text-align: inherit">

View File

@@ -38,6 +38,8 @@ export default function Index() {
}, [publicKeyB64, privateKeyB64, pairingCode]);
const pollTick = async () => {
if (!publicKeyB64 || !privateKeyB64 || !pairingCode) return;
const registration = { publicKeyB64, privateKeyB64, pairingCode };
try {
const data = await getCastData(registration);

View File

@@ -9,9 +9,8 @@ import { isChromecast } from "services/chromecast";
import { imageURLGenerator } from "services/render";
export default function Slideshow() {
const [loading, setLoading] = useState(true);
const [imageURL, setImageURL] = useState<string | undefined>();
const [isEmpty, setIsEmpty] = useState(false);
const [imageURL, setImageURL] = useState<string | undefined>();
const router = useRouter();
@@ -35,7 +34,6 @@ export default function Slideshow() {
}
setImageURL(url);
setLoading(false);
}
} catch (e) {
log.error("Failed to prepare generator", e);
@@ -50,8 +48,8 @@ export default function Slideshow() {
};
}, []);
if (loading) return <PairingComplete />;
if (isEmpty) return <NoItems />;
if (!imageURL) return <PairingComplete />;
return isChromecast() ? (
<SlideViewChromecast url={imageURL} />

View File

@@ -19,8 +19,8 @@ export const storeCastData = (payload: unknown) => {
// Iterate through all the keys of the payload object and save them to
// localStorage. We don't validate here, we'll validate when we read these
// values back in `readCastData`.
for (const key in payload) {
window.localStorage.setItem(key, payload[key]);
for (const [key, value] of Object.entries(payload)) {
window.localStorage.setItem(key, value);
}
};

View File

@@ -141,6 +141,7 @@ const advertiseCode = (cast: Cast) => {
const collectionID =
data &&
typeof data == "object" &&
"collectionID" in data &&
typeof data["collectionID"] == "string"
? data["collectionID"]
: undefined;

View File

@@ -13,7 +13,7 @@ import FileType from "file-type";
* For the list of returned extensions, see (for our installed version):
* https://github.com/sindresorhus/file-type/blob/main/core.d.ts
*/
export const detectMediaMIMEType = async (file: File): Promise<string> => {
export const detectMediaMIMEType = async (file: File) => {
const chunkSizeForTypeDetection = 4100;
const fileChunk = file.slice(0, chunkSizeForTypeDetection);
const chunk = new Uint8Array(await fileChunk.arrayBuffer());

View File

@@ -81,7 +81,7 @@ export const register = async (): Promise<Registration> => {
await generateKeyPair();
// Register keypair with museum to get a pairing code.
let pairingCode: string;
let pairingCode: string | undefined;
// eslint has fixed this spurious warning, but we're not on the latest
// version yet, so add a disable.
// https://github.com/eslint/eslint/pull/18286

View File

@@ -7,6 +7,7 @@ import { nameAndExtension } from "@/next/file";
import log from "@/next/log";
import type { ComlinkWorker } from "@/next/worker/comlink-worker";
import { shuffled } from "@/utils/array";
import { ensure } from "@/utils/ensure";
import { wait } from "@/utils/promise";
import ComlinkCryptoWorker from "@ente/shared/crypto";
import { ApiError } from "@ente/shared/error";
@@ -15,7 +16,7 @@ import { apiOrigin, customAPIOrigin } from "@ente/shared/network/api";
import type { AxiosResponse } from "axios";
import type { CastData } from "services/cast-data";
import { detectMediaMIMEType } from "services/detect-type";
import {
import type {
EncryptedEnteFile,
EnteFile,
FileMagicMetadata,
@@ -133,7 +134,7 @@ export const imageURLGenerator = async function* (castData: CastData) {
// The last to last element is the one that was shown prior to that,
// and now can be safely revoked.
if (previousURLs.length > 1)
URL.revokeObjectURL(previousURLs.shift());
URL.revokeObjectURL(ensure(previousURLs.shift()));
previousURLs.push(url);
@@ -207,8 +208,8 @@ const decryptEnteFile = async (
metadata.decryptionHeader,
fileKey,
);
let fileMagicMetadata: FileMagicMetadata;
let filePubMagicMetadata: FilePublicMagicMetadata;
let fileMagicMetadata: FileMagicMetadata | undefined;
let filePubMagicMetadata: FilePublicMagicMetadata | undefined;
if (magicMetadata?.data) {
fileMagicMetadata = {
...encryptedFile.magicMetadata,
@@ -242,6 +243,8 @@ const decryptEnteFile = async (
if (file.pubMagicMetadata?.data.editedName) {
file.metadata.title = file.pubMagicMetadata.data.editedName;
}
// @ts-expect-error TODO: The core types need to be updated to allow the
// possibility of missing metadata fiels.
return file;
};
@@ -254,7 +257,7 @@ const isFileEligible = (file: EnteFile) => {
// extension. To detect the actual type, we need to sniff the MIME type, but
// that requires downloading and decrypting the file first.
const [, extension] = nameAndExtension(file.metadata.title);
if (isNonWebImageFileExtension(extension)) {
if (extension && isNonWebImageFileExtension(extension)) {
// Of the known non-web types, we support HEIC.
return isHEICExtension(extension);
}

View File

@@ -1,5 +1,5 @@
import type { Metadata } from "@/media/types/file";
import {
import type {
EncryptedMagicMetadata,
MagicMetadataCore,
VISIBILITY_STATE,

View File

@@ -1,25 +1,17 @@
{
"extends": "../../tsconfig.base.json",
"extends": "@/build-config/tsconfig-next.json",
"compilerOptions": {
/* Set the base directory from which to resolve bare module names */
"baseUrl": "./src",
"downlevelIteration": true,
"jsx": "preserve",
"jsxImportSource": "@emotion/react",
"lib": ["dom", "dom.iterable", "esnext", "webworker"],
"noImplicitAny": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"strictNullChecks": false,
"target": "es5",
"useUnknownInCatchVariables": false
/* TODO(MR): Enable this */
"noUncheckedIndexedAccess": false,
/* MUI doesn't play great with exactOptionalPropertyTypes currently. */
"exactOptionalPropertyTypes": false
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"**/*.js",
"../../packages/shared/themes/mui-theme.d.ts",
"../../packages/accounts/**/*.tsx"
],
"exclude": ["node_modules", "out", ".next", "thirdparty"]
"src",
"../../packages/next/global-electron.d.ts",
"../../packages/shared/themes/mui-theme.d.ts"
]
}