Compare commits

..

218 Commits

Author SHA1 Message Date
Neeraj Gupta
6146350aae [docs] Update custom server section for cli 2024-03-13 12:02:36 +05:30
Vishnu Mohandas
f8d8550b10 v0.8.68 (#1076) 2024-03-13 11:47:47 +05:30
vishnukvmd
bc4fa44edd v0.8.68 2024-03-13 11:47:25 +05:30
Vishnu Mohandas
92de88e778 [photos] Update flow for Independent APK (#1074) 2024-03-13 11:46:04 +05:30
Vishnu Mohandas
7814cbcc91 Remove unused code for app-updates (#1072) 2024-03-13 11:45:53 +05:30
Ashil
518b947808 [mobile][photos] Make scrollbar in log file viewer interactive (#1075) 2024-03-13 11:43:31 +05:30
Neeraj Gupta
077ba04664 [cli-release.yml] Pass release version in build flag 2024-03-13 11:43:19 +05:30
Neeraj Gupta
e42422407c [cli] Pick version from the github tag 2024-03-13 11:43:19 +05:30
Neeraj Gupta
2711a227fc [cli] Update gen docs + add docs/selfhost.md 2024-03-13 11:43:19 +05:30
Neeraj Gupta
4325de6fde [mob] Remove .env.example 2024-03-13 11:43:19 +05:30
Neeraj Gupta
c7d7d436c3 [docs] Add guide to connect CLI to self-hosted instance 2024-03-13 11:43:19 +05:30
Neeraj Gupta
f7077c2b11 [docs] Update guide to build mobile app 2024-03-13 11:43:19 +05:30
vishnukvmd
8f525cb88d Update Github Action for Photos 2024-03-13 11:27:24 +05:30
vishnukvmd
be3b4dc7ba Open the link to Github APK instead of downloading it in-app 2024-03-13 11:21:36 +05:30
Ashil
0c1c0ad400 [mobile][photos] Home widget UI tweaks (#1060) 2024-03-13 11:20:50 +05:30
Ashil
773f4cdca2 [mobile][photos] Fix missing hero animation (#1064)
## Description

Sometimes, when opening an image from gallery, the hero animation fails
to happen. This PR fixes this issue.



https://github.com/ente-io/ente/assets/77285023/2ee40ec8-58d0-4ca1-82fb-1be96581137b



## Tests

- [x] Didn't break hero animations of videos, it almost stays the same.
2024-03-13 11:20:20 +05:30
Manav Rathi
96bb79b9e9 [web] Allow running the build outside of a git repository (#1073)
This was found useful by @Bramas when building a Dockerfile of the web
app itself. See https://github.com/ente-io/ente/pull/1065.

Now, the GIT_SHA environment variable can just be undefined if we're not
in a git repository, and the code using it deals with that case
explicitly.

**Tested by**

Temporarily inverted the isDevBuild flag, then

1. Ran the build normally and verified that the SHA continued to appear
in the logs.

2. Ran the build after copying to a standalone folder without an
associated git repository and verified that the SHA was skipped without
causing the build to fail.
2024-03-13 11:19:44 +05:30
Manav Rathi
d5164693ff Fix vitepress warning
Change the syntax highlighting of the `env` code block from `env` to `sh`
because currently vite press doesn't support the env language and instead
complains

> The language 'env' is not loaded, falling back to 'txt' for syntax highlighting.
2024-03-13 11:17:53 +05:30
Manav Rathi
26b162c8dc [web] Allow running the build outside of a git repository
This was found useful by @Bramas when building a Dockerfile of the web app
itself. See https://github.com/ente-io/ente/pull/1065.

Now, the GIT_SHA environment variable can just be undefined if we're not in a
git repository, and the code using it deals with that case explicitly.

**Tested by**

Temporarily inverted the isDevBuild flag, tehn

1. Ran the build normally and verified that the SHA continued to appear in the logs.

2. Ran the build after copying to a standalone folder without an associated git
   repository and verified that the SHA was skipped without causing the build to
   fail.
2024-03-13 11:15:12 +05:30
Neeraj Gupta
297148dc67 [auth][mob] Add recovery support for passkey (#1013)
## Description

## Tests
  Verified that reset flow is working fine on both auth and photos app.
2024-03-13 11:12:30 +05:30
vishnukvmd
46522c329c Remove unused code for app-updates 2024-03-13 11:12:06 +05:30
Manav Rathi
8358eef34e [docs] Move the self hosting using external S3 buckets guide to independent page (#1070)
See: https://github.com/ente-io/ente/pull/1066
2024-03-13 10:44:12 +05:30
Manav Rathi
4326409046 [docs] Move the self hosting using external S3 buckets guide to independent page
See: https://github.com/ente-io/ente/pull/1066
2024-03-13 10:32:35 +05:30
Manav Rathi
687d575bf4 add guide for self-hosting server + webapp with external S3 storage (#1066)
## Description

I wrote a small guide to run the server and the web app using docker
compose (locally or on a server), with an external S3 storage (which I
assume will be a common use-case).

It requires #1065 , or at least this line change:
https://github.com/ente-io/ente/pull/1065/files#diff-5a9426639947f5afb92612a4583a5b7d496f9cb6a791db9c29f28ff298282aebR16
2024-03-13 09:55:24 +05:30
Neeraj Gupta
0678e3129a [cli] generated docs 2024-03-13 02:03:44 +05:30
Neeraj Gupta
b164b0df21 [cli] By default, update sub to high storage & expiry 2024-03-13 02:03:44 +05:30
Neeraj Gupta
0d38346722 [cli] Add admin API to bump up storage for free users 2024-03-13 02:03:44 +05:30
Neeraj Gupta
51d3238a52 [cli] Log query params in debug mode 2024-03-13 02:03:44 +05:30
Neeraj Gupta
ddd89aa1d1 [cli] Log query params in debug mode 2024-03-13 02:03:44 +05:30
Neeraj Gupta
f21a627a71 Add cli generated docs inside docs/generated 2024-03-13 02:03:44 +05:30
Neeraj Gupta
063e980280 [cli] Add command to get-token 2024-03-13 02:03:44 +05:30
Neeraj Gupta
d7d42b6854 [cli] Add example config file 2024-03-13 02:03:44 +05:30
Neeraj Gupta
260a7fbcaa [cli] Allow switching API host based on config 2024-03-13 02:03:44 +05:30
Quentin Bramas
55e0ec39ed add guide for self-hosting server + webapp with external S3 storage 2024-03-12 15:14:35 +01:00
Manav Rathi
9c04a7102b [desktop] Fix desktop dev builds - Part 1 (#1063)
- Main change here is removing a submodule and moving to the upstream
dependency
- Also updated to Prettier 3

The original issue, about yarn dev not working because of context
isolation, still remains. This PR prepares the ground, will have a go at
it in a subsequent PR.
2024-03-12 18:03:10 +05:30
Manav Rathi
a5e6f0cc30 Let Prettier 3 have a go at it 2024-03-12 18:01:09 +05:30
Manav Rathi
2322b41f67 Watch during dev 2024-03-12 17:56:46 +05:30
Manav Rathi
685e75d97d Switch to upstream 2024-03-12 17:38:39 +05:30
Manav Rathi
cde87716a1 Remove the custom next-electron-server
The only change this has in addition to next-electron-server seems to be
https://github.com/ente-io/next-electron-server/pull/1/files, will try to test
along the way to determine its impact.
2024-03-12 17:02:28 +05:30
Manav Rathi
dff0af3397 Fix path to main process entrypoint 2024-03-12 16:47:41 +05:30
Manav Rathi
ca771993ee [desktop] Fix desktop build (#1062)
`yarn dev` is still not working, but that is a previous issue unrelated
to the monorepo migration. Will fix that in a subsequent PR.
2024-03-12 16:38:06 +05:30
Manav Rathi
c8b9b4cd8f Document better 2024-03-12 16:33:43 +05:30
Manav Rathi
d7cd2cecbc Default buildResources is build 2024-03-12 16:12:53 +05:30
Manav Rathi
e219197e2f Fix import 2024-03-12 15:07:06 +05:30
Manav Rathi
3eb84ceba8 [web] New translations (#1058)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2024-03-12 14:22:28 +05:30
Manav Rathi
e358738c35 [workflows] Prevent duplicate runs of lint workflows after merging a PR (#1059) 2024-03-12 14:21:46 +05:30
Manav Rathi
b15901df67 [workflows] Prevent duplicate runs of lint workflows after merging a PR 2024-03-12 14:14:18 +05:30
Crowdin Bot
ee7d90e55b New Crowdin translations by GitHub Action 2024-03-12 08:38:32 +00:00
Manav Rathi
22b744aa96 [web] [desktop] Remove Sentry (#1057)
Sentry has a measurable impact on page load, a metric that I'm keen to
improve. Apparently by default it loses us 8-9 page speed points, though
that can be reduced to 3-4
(https://github.com/getsentry/sentry-javascript/issues/9179).

All of this is doable, but there are bigger tasks to deal with. This is
not to say that Sentry won't be useful again at some point, when we have
time to deal with it better. But right now, we discussed that it's just
better to remove Sentry instead of piling on to the sunk cost.
2024-03-12 14:07:29 +05:30
Manav Rathi
5d01931402 Retain -web suffix to allow disambiguating between main and renderer process 2024-03-12 14:06:42 +05:30
Manav Rathi
206ad46950 Remove CRASH_REPORTING key 2024-03-12 13:59:45 +05:30
Manav Rathi
9b6e47d291 [desktop] Remove sentry
See 70cddfdf0b
2024-03-12 13:54:17 +05:30
Manav Rathi
70cddfdf0b [web] Remove Sentry
Sentry has a measurable impact on page load, a metric that I'm keen to
improve. Apparently by default it loses us 8-9 page speed points, though that
can be reduced to 3-4
(https://github.com/getsentry/sentry-javascript/issues/9179).

All of this is doable, but there are bigger tasks to deal with. This is not to
say that Sentry won't be useful again at some point, when we have time to deal
with it better. But right now, we discussed that it's just better to remove
Sentry instead of piling on to the sunk cost.
2024-03-12 13:24:33 +05:30
Neeraj Gupta
c0a2347b80 [server] Refactor /user/plans 2024-03-12 12:17:04 +05:30
Manav Rathi
dd556f8f72 [server] Fix uploads on self-hosted Docker when running on Windows (#1056)
On our Discord @Degos ran into an issue where their uploads to the self
hosted docker compose cluster were failing. On debugging, it was found
that the line-endings in `server/scripts/compose/minio-provision.sh`
were set to CRLF, causing the script to fail when run inside Docker. The
minIO buckets never got provisioned, and so the uploads would fail with

    <Code>NoSuchBucket</Code>
    <Message>The specified bucket does not exist</Message>


![image](https://github.com/ente-io/ente/assets/24503581/37945ed3-3c52-4796-8092-47be6e4a85da)

To fix this, we add a new .gitattributes that enforces the LF for the
scripts that run inside Docker. To (perhaps too preemptively) guard
against similar issues in other scenarios, turn this on for all shell
scripts.

Refs:
-
https://stackoverflow.com/questions/29603737/bash-seamlessly-run-scripts-with-crlf-line-endings
-
https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings
2024-03-12 12:00:13 +05:30
Manav Rathi
2fc1a96c8b [server] Fix uploads on self-hosted Docker when running on Windows
On our Discord @Degos ran into an issue where their uploads to the self hosted
docker compose cluster were failing. On debugging, it was found that the
line-endings in `server/scripts/compose/minio-provision.sh` were set to CRLF,
causing the script to fail when run inside Docker. The minIO buckets never got
provisioned, and so the uploads would fail with

    <Code>NoSuchBucket</Code>
    <Message>The specified bucket does not exist</Message>

To fix this, we add a new .gitattributes that enforces the LF for the scripts
that run inside Docker. To (perhaps too preemptively) guard against similar
issues in other scenarios, turn this on for all shell scripts.

Refs:
- https://stackoverflow.com/questions/29603737/bash-seamlessly-run-scripts-with-crlf-line-endings
- https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings
2024-03-12 11:57:41 +05:30
Manav Rathi
8a7f64b889 [web] New translations (#1049)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2024-03-12 11:28:39 +05:30
Manav Rathi
c153b28ed6 [web] Support preview deployments (#1052)
Preview deployments can be made by manually triggering the "Preview
(web)" workflow. You can select the app you want to build
(accounts/auth/cast/photos) and the branch to take the code from. The
deployment will be available at https://preview.ente.sh.
2024-03-12 10:11:56 +05:30
Manav Rathi
a9557df240 Add preview deployment docs 2024-03-12 10:08:52 +05:30
Manav Rathi
8c23090abd Remove placeholders 2024-03-12 09:56:07 +05:30
Manav Rathi
6efe2cd5fd Add a push trigger to register the workflow
See https://stackoverflow.com/questions/63362126/github-actions-how-to-run-a-workflow-created-on-a-non-master-branch-from-the-wo
2024-03-12 09:53:58 +05:30
Manav Rathi
4feea01879 [web] Support preview deployments 2024-03-12 09:52:34 +05:30
Neeraj Gupta
51f19cf2fd [web] Fix lint error 2024-03-12 09:33:14 +05:30
Neeraj Gupta
dbc50760af [web][passkey] Whitelist *.ente.sh redirect urls 2024-03-12 09:33:14 +05:30
Neeraj Gupta
638de0a769 [authw] Handle passkey finish redirect 2024-03-12 09:33:14 +05:30
Neeraj Gupta
0ab1c0ee89 [mob] gitignore android/.settings 2024-03-12 09:33:14 +05:30
Neeraj Gupta
cb8738287a [photosw] Enable passkey for internal users 2024-03-12 09:33:14 +05:30
ashilkn
ddedaf2d0e bump up version to v0.8.67 2024-03-12 07:51:57 +05:30
Crowdin Bot
cfa4077b5c New Crowdin translations by GitHub Action 2024-03-12 01:36:05 +00:00
Prateek Sunal
1d2de8d9b8 [mobile][photos] Home Widget fixes (#992)
## Description

- Upscale default placeholder
- Keep image ready to be rendered in home widget before adding the home
widget.
- Change the photo in home widget every time it's clicked.
- Open favourites when home widget is clicked.
- Fix multiple issues

## Tests

Did a good amount of testing.

---------

Co-authored-by: ashilkn <ashilkn99@gmail.com>
Co-authored-by: Ashil <77285023+ashilkn@users.noreply.github.com>
2024-03-12 01:39:30 +05:30
Neeraj Gupta
e843ea6669 [server] Change param type from uuid to string 2024-03-11 22:45:53 +05:30
Neeraj Gupta
9f2a66e0ef Fix lint warnings 2024-03-11 22:45:22 +05:30
Neeraj Gupta
944ef2e564 [mob]Generate randomkey using crypto library 2024-03-11 22:34:00 +05:30
Manav Rathi
00f45ef39d [photosd] Fix desktop build - part 2 (#1044)
The build is still not fixed, but this is a step closer to where we want
to be.
2024-03-11 18:53:09 +05:30
Manav Rathi
84926cbee1 build take 2 2024-03-11 18:52:28 +05:30
Neeraj Gupta
27c1b66c08 [auth][mob] Add recovery support for passkey 2024-03-11 17:54:24 +05:30
Manav Rathi
027ae1cfb9 build => resources 2024-03-11 17:37:43 +05:30
Manav Rathi
621f81355b Work towards fixing build 2024-03-11 17:37:10 +05:30
Manav Rathi
849b61c5cf Document some and fix the path 2024-03-11 17:29:39 +05:30
Manav Rathi
267ad0d11f [desktop] Fix yarn build 2024-03-11 17:04:17 +05:30
Neeraj Gupta
e272722d6e [mob][photos] Add dialog to describe clean uncat option 2024-03-11 16:52:27 +05:30
Neeraj Gupta
a73f3cc52b [mob] Fixed sorting bug in uncategorized section 2024-03-11 16:52:27 +05:30
Manav Rathi
748d18cc2a [photosd] Format using Prettier (#1010)
This is part 1 of general fixes to get the Photos desktop app back up
and building after moving to this monorepo. The main change in this PR
is to reformat the source to match the prettier config for the other
JS/TS (web/, docs/) code. And a few other fixes.

It still doesn't build, and there are a few eslint errors too. Those
will come in a subsequent PR.
2024-03-11 16:49:20 +05:30
Manav Rathi
88741083fe Prettier 3 + reformat (same as web) 2024-03-11 16:46:52 +05:30
Manav Rathi
829406fa62 Tweak .gitignore 2024-03-11 16:38:32 +05:30
Manav Rathi
df13eac6ef Remove unused files 2024-03-11 16:35:00 +05:30
Manav Rathi
25dda3598c Remove husky and lint-staged 2024-03-11 16:31:48 +05:30
Neeraj Gupta
9a8e76b494 [docs] Fix the location for auth faq 2024-03-11 16:14:38 +05:30
Neeraj Gupta
c6120f33de [docs] Copy Auth FAQ from mobile app 2024-03-11 16:05:56 +05:30
Manav Rathi
200504dc01 [web] New translations (#1007)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2024-03-11 16:03:57 +05:30
Crowdin Bot
2a33707db2 New Crowdin translations by GitHub Action 2024-03-11 10:29:16 +00:00
Manav Rathi
3fd5af8134 [web] Various small internal improvements (#1006)
- to the web alias for shared albums during nightly deployments
- Remove duplicate favicon link
- Capitalize Ente
- Document translation
- Remove the unnecessary console warning
2024-03-11 15:58:16 +05:30
Neeraj Gupta
bb68b22adb [server] mark queue as deprecated 2024-03-11 15:41:18 +05:30
Neeraj Gupta
5accf4c6a8 [server] Remove dead code related to collecton trashV2 2024-03-11 15:41:18 +05:30
Neeraj Gupta
28335700e3 [server] Remove deprecated API 2024-03-11 15:41:18 +05:30
Manav Rathi
e3826695c5 Remove the unnecessary console warning 2024-03-11 15:31:46 +05:30
Manav Rathi
6fdfa24e89 Document translation 2024-03-11 15:30:24 +05:30
Vishnu Mohandas
fb2abd8afc [mobile][photos]Rediscovery tab fixes (#1003)
## Description

Changed,
1. Section title in the discovery page
2. Page title in the page that pops up on tapping the > next to the
header on the discovery page

for Location and Description section.
2024-03-11 15:24:33 +05:30
Manav Rathi
bd84b54c5a Capitalize Ente 2024-03-11 13:27:17 +05:30
Manav Rathi
af4eaac158 Remove duplicate favicon link 2024-03-11 13:26:15 +05:30
Manav Rathi
de166645b0 Point to the web alias for shared albums during nightly deployments 2024-03-11 13:20:58 +05:30
ashilkn
ae67f0d67b nit: change description section's heading from 'Photo descriptions' to 'Descriptions' 2024-03-11 13:06:07 +05:30
ashilkn
fab16a7947 nit: change location section's heading from 'Location' to 'Locations' 2024-03-11 12:59:59 +05:30
Neeraj Gupta
9711e0e29e Improve log 2024-03-11 12:34:03 +05:30
Neeraj Gupta
d7292dc670 [server] Release locks before initiating any other controller 2024-03-11 12:34:03 +05:30
Neeraj Gupta
6930aaf220 [server]Update freq for metadatacron 2024-03-11 12:34:03 +05:30
Neeraj Gupta
12903a3748 [server] Clean up collecitonDiff logs 2024-03-11 12:34:03 +05:30
Manav Rathi
412c872266 [web] Fix shared albums (#1001)
This flow probably got broken when the select-all-for-a-day
functionality got added in https://github.com/ente-io/ente/pull/674
(haven't dug into this, I'm just guessing since that's where this all
got touched).

Thank you to @Bramas on our Discord for pointing this out, and also
providing the fix:
https://github.com/ente-io/ente/compare/main...Bramas:ente:fix-error-on-shared-album

Tested by
---------

Run normal web app on one terminal

NEXT_PUBLIC_ENTE_ENDPOINT=http://localhost:8080
NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=http://localhost:3002 yarn dev

Run the albums listener on another port (need to do this since we're
running on localhost, and need to bind to a different origin):

NEXT_PUBLIC_ENTE_ENDPOINT=http://localhost:8080
NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=http://localhost:3002 yarn dev:albums

Create a shared album, copy its public link, and verify that

- Before the fix we were getting an error (trying to access properties
of `galleryContext.selectedFile`)
- After the fix the shared album is visible
2024-03-11 12:05:07 +05:30
Manav Rathi
8fab6b5e48 [web] Fix shared albums
This flow probably got broken when the select-all-for-a-day functionality got
added in https://github.com/ente-io/ente/pull/674 (haven't dug into this, I'm
just guessing since that's where this all got touched).

Thank you to @Bramas on our Discord for pointing this out, and also providing the fix:
https://github.com/ente-io/ente/compare/main...Bramas:ente:fix-error-on-shared-album

Tested by
---------

Run normal web app on one terminal

    NEXT_PUBLIC_ENTE_ENDPOINT=http://localhost:8080 NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=http://localhost:3002 yarn dev

Run the albums listener on another port (need to do this since we're running on
localhost, and need to bind to a different origin):

    NEXT_PUBLIC_ENTE_ENDPOINT=http://localhost:8080 NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=http://localhost:3002 yarn dev:albums

Create a shared album, copy its public link, and verify that

- Before the fix we were getting an error (trying to access properties of `galleryContext.selectedFile`)
- After the fix the shared album is visible
2024-03-11 12:00:26 +05:30
Neeraj Gupta
4af3030c81 [server] Speed up RemoveComplianceHolds 2024-03-11 11:43:02 +05:30
Neeraj Gupta
c32f0a28f1 [server] Release previous locks taken by host on statup 2024-03-11 11:43:02 +05:30
Manav Rathi
38e8f7c8d7 [web] New translations (#748)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2024-03-11 11:09:18 +05:30
Vishnu Mohandas
72aa597f85 Update custom-icons.json (#979)
## Description

After this commit https://github.com/ente-io/ente/pull/430 those 6 icons
I tried to add do not shows the icon or default letter, but icon is
filled with hexcolor, so I guess hexcolor is not needed.
2024-03-11 11:01:44 +05:30
Manav Rathi
f759ce07ae [docs] Add a workflow to do a preflight verification of build on each PR (#999)
Tested by opening this PR and verifying that the verify build workflow
succeeded. Say verify one more time, I dare you...
2024-03-11 11:01:38 +05:30
Manav Rathi
976a76ae23 [docs] Add a workflow to do a preflight verification of build on each PR 2024-03-11 10:59:47 +05:30
Neeraj Gupta
89d761a096 Reduce lock duration 2024-03-11 10:39:46 +05:30
Neeraj Gupta
e667eef951 Tweak speed for crons 2024-03-11 10:39:46 +05:30
Manav Rathi
192caedeb9 [docs] Fix build + run prettier (#997) 2024-03-11 10:32:21 +05:30
Manav Rathi
fc482609b6 Fix build 2024-03-11 10:31:42 +05:30
Manav Rathi
e1e0c45d88 yarn pretty 2024-03-11 10:31:07 +05:30
Manav Rathi
8f384247ba [docs] Add more self-hosting instructions (#996)
- How to set custom server
- How to build for mobile

/ping @ua741 @vishnukvmd
2024-03-11 10:29:07 +05:30
Manav Rathi
b0d396a5bd [docs] Add more self-hosting instructions
- How to set custom server
- How to build for mobile
2024-03-11 10:28:20 +05:30
Crowdin Bot
2354f5bc7e New Crowdin translations by GitHub Action 2024-03-11 01:36:36 +00:00
Vishnu Mohandas
73b4f54d42 [auth] v2.0.42 (#989) 2024-03-10 21:54:22 +05:30
vishnukvmd
ccd9e2ecaf [auth] v2.0.42 2024-03-10 21:53:05 +05:30
Vishnu Mohandas
4f3d9d0798 [docs] Add article on sharing (#984) 2024-03-09 23:31:40 +05:30
vishnukvmd
5ffa8ffe2b [docs] Add article on sharing 2024-03-09 23:31:20 +05:30
Vishnu Mohandas
50cb7f7aaf [mob][photos] Update version and change log (#981)
## Description

- Updated change log.
- Some final changes.
- Bumped up to `v0.8.66`

### Change Log

#### iOS


https://github.com/ente-io/ente/assets/77285023/10e0d1a3-cdfc-4431-be6c-1eb8718d35db

#### Android


https://github.com/ente-io/ente/assets/77285023/fed1e917-da2e-4001-b167-25fa72a1ff8c



## Tests
- [x] Builds fine on iOS and Android.
2024-03-09 19:26:32 +05:30
ashilkn
8daa7d8a8e remove worker manager related changes 2024-03-09 17:19:15 +05:30
ashilkn
5dbc300056 bump up to v0.8.66 2024-03-09 17:17:18 +05:30
iamgitcat
c7a4507f96 Update custom-icons.json
After this commit https://github.com/ente-io/ente/pull/430 those 6 icons I tried to add do not shows the icon or default letter, but icon is filled with hexcolor, so I guess hexcolor is not needed.
2024-03-09 14:45:44 +03:00
ashilkn
b812827480 update currentChangeLogVersion 2024-03-09 17:15:08 +05:30
ashilkn
f9051c94da update change log 2024-03-09 17:12:57 +05:30
ashilkn
4c3642526e minor fix 2024-03-09 17:05:23 +05:30
ashilkn
7c86e8f903 update limit of elemets shown in each search section 2024-03-09 16:52:02 +05:30
ashilkn
b4cf5761fa remove unused translation 2024-03-09 16:44:24 +05:30
ashilkn
881ece525f fix alignment of 'search' hint text in search field 2024-03-09 16:39:54 +05:30
Prateek Sunal
5acef45118 [FIX] HomeWidget improvements (#737)
## Description
- Use Background fetch as workmanager is not working as expected.
- Use new asset for empty state.
2024-03-09 16:21:04 +05:30
Vishnu Mohandas
96d1b09147 [auth] v2.0.41 (#777) 2024-03-09 11:24:44 +05:30
vishnukvmd
fc390d69c7 [auth] v2.0.41 2024-03-09 11:24:15 +05:30
Manav Rathi
c49cee8be6 [web] Fix a warning about MUI component switch state on using the select all checkbox (#774)
The issue here was that since the checkbox property would get
initialized to an undefined value, React would consider it to be
uncontrolled. But later on we'd try to set a value, which'd cause React
to complain.

Ref:
- Material-UI: A component is changing the uncontrolled checked state of
SwitchBase to be controlled

https://stackoverflow.com/questions/69259429/material-ui-a-component-is-changing-the-uncontrolled-checked-state-of-switchbas
2024-03-09 09:47:46 +05:30
Manav Rathi
8c9a11fc62 [web] Fix a warning about MUI component switch state on using the select all checkbox
The issue here was that since the checkbox property would get initialized to an
undefined value, React would consider it to be uncontrolled. But later on we'd
try to set a value, which'd cause React to complain.

Ref:
- Material-UI: A component is changing the uncontrolled checked state of SwitchBase to be controlled
  https://stackoverflow.com/questions/69259429/material-ui-a-component-is-changing-the-uncontrolled-checked-state-of-switchbas
2024-03-09 09:42:33 +05:30
Vishnu Mohandas
50b50409b1 [auth] Remove awaits (#773) 2024-03-09 08:42:30 +05:30
Vishnu Mohandas
b52cf1605d Merge branch 'main' into remove_awaits 2024-03-09 08:42:04 +05:30
Manav Rathi
c14f2ddbd7 [docs] Add a note about how to get the OTT on self hosted instance (#771)
Documentation only change.
2024-03-08 23:07:37 +05:30
Manav Rathi
a9c6196142 [docs] Add a note about how to get the OTT on self hosted instance 2024-03-08 23:06:50 +05:30
Manav Rathi
2ed8429df8 [docs] Fix build error and add a Yarn troubleshooting page (#770)
Docs only change.
2024-03-08 21:22:05 +05:30
Manav Rathi
c899984f76 Add yarn troubleshooting page 2024-03-08 21:21:10 +05:30
Manav Rathi
ed3b165b4b Don't consider localhost links as dead
Fixes the following error when building the site

    (!) Found dead link http://localhost:3000 in file self-hosting/index.md
    x Build failed in 1.72s
    If this is expected, you can disable this check via config. Refer: https://vitepress.dev/reference/site-config#ignoredeadlinks
2024-03-08 21:17:00 +05:30
Manav Rathi
20940293d3 [docs] Add self-hosting section and add getting started docs (#769)
Documentation only changed. Verified the preview by running docs server
locally.
2024-03-08 21:11:47 +05:30
Manav Rathi
f040ffad13 [docs] Add self-hosting section and add getting started docs 2024-03-08 21:09:49 +05:30
vishnukvmd
33f12ffd9d Up version 2024-03-08 20:14:07 +05:30
vishnukvmd
b0f8e331e6 Remove unnecessary awaits 2024-03-08 20:13:41 +05:30
Vishnu Mohandas
e9d46a8093 [auth] Up version (#760) 2024-03-08 18:28:49 +05:30
vishnukvmd
ca90727c78 [auth] Up version 2024-03-08 18:28:04 +05:30
Vishnu Mohandas
440b6b2833 Update links to Auth releases (#758) 2024-03-08 17:41:52 +05:30
vishnukvmd
3e7862fe4e Update links to Auth releases 2024-03-08 17:41:34 +05:30
Manav Rathi
f0f81d2ec2 Update sharing-logs.md (#757)
Test commit to test the flow.
2024-03-08 17:21:18 +05:30
Manav Rathi
eb28279de0 Update sharing-logs.md 2024-03-08 17:20:21 +05:30
Vishnu Mohandas
c75e45897c [Photos] Fix auto scaling on loading final image (#749)
## Description

When an image is zoomed in, there were cases where when then final image
is loaded and rendered on screen, the image gets zoomed even more.

#### Case 1
Double tapping twice to zoom and then the final image is loaded.

##### Before


https://github.com/ente-io/ente/assets/77285023/7d9acb0f-2849-4ffb-863d-cab61ef4bd16

##### After


https://github.com/ente-io/ente/assets/77285023/89fb1238-1444-4681-a94f-7a58679f9350



#### Case 2
When screen is pressed or dragged (any contact with screen).

##### Before


https://github.com/ente-io/ente/assets/77285023/3aefdec5-3bc3-42ef-9442-592442273569

##### After


https://github.com/ente-io/ente/assets/77285023/7b458184-5abe-4983-ba21-f38080cc8bee

## Tests

Tested for regressions. Found one, which it not quite a regression as
the issue was already present but reproducible in a different flow. It
happens too fast for screen recording to capture it.

Not a blocker as it doesn't affect usability in anyway and since this
fix (auto scaling on final image loading) is an important fix.
2024-03-08 17:05:24 +05:30
ashilkn
62b05513a2 Remove late initialisations 2024-03-08 17:00:48 +05:30
Manav Rathi
353eb67cab [web] Finalize deployment process (#755)
These changes were all made in previous PRs, this PR just ties up the
loose ends and updates the documentation etc.
2024-03-08 16:46:59 +05:30
Manav Rathi
290196ee9e Add fixed nightly mappings 2024-03-08 16:36:06 +05:30
ashilkn
ea63ea1c55 Make _photoViewController late 2024-03-08 16:32:16 +05:30
Manav Rathi
2d14cc5899 Mention fast forwards 2024-03-08 16:29:35 +05:30
Manav Rathi
f612e0b69f Published 2024-03-08 16:24:37 +05:30
Manav Rathi
929e1bbac1 Less preachy 2024-03-08 16:17:53 +05:30
ashilkn
1dd183c4bd Make scaleStateController final and dispose it when widget gets disposed 2024-03-08 15:54:38 +05:30
Manav Rathi
bcb0e2fcc3 [web] Add production deployment templates (#751)
Also update the documentation.
2024-03-08 15:50:39 +05:30
Manav Rathi
25a04fbc5f Update docs README 2024-03-08 15:49:13 +05:30
Manav Rathi
0b585ce3a5 Update the documentation 2024-03-08 15:40:35 +05:30
Manav Rathi
8058d2bfd4 Add production deployments 2024-03-08 15:20:16 +05:30
Neeraj Gupta
5a04030766 Fix lint 2024-03-08 15:17:28 +05:30
Neeraj Gupta
04e508561b [photos] Update copy for passkey verification 2024-03-08 15:17:28 +05:30
Neeraj Gupta
57d5647a39 [photos] Add support for by-passing passkey 2024-03-08 15:17:28 +05:30
Neeraj Gupta
9f28e5ef79 Rename 2024-03-08 15:17:28 +05:30
Neeraj Gupta
42d9ad4206 [photos] Register passkey reset key 2024-03-08 15:17:28 +05:30
Neeraj Gupta
907a0bd456 Reformat 2024-03-08 15:17:28 +05:30
Neeraj Gupta
8f37af3985 [mobile] Add TwoFactorType enum & pass it during recovery 2024-03-08 15:17:28 +05:30
Neeraj Gupta
6e160dca43 Fix minor bugs 2024-03-08 15:15:00 +05:30
Neeraj Gupta
1f7d9dbb86 Rename passKey to passkey 2024-03-08 15:15:00 +05:30
Neeraj Gupta
a780598607 Fix sql query 2024-03-08 15:15:00 +05:30
Neeraj Gupta
7f66714d96 Refactor + bug fixes 2024-03-08 15:15:00 +05:30
Neeraj Gupta
980ab6c49c Refactor: extend totp recovery API to recover passkey 2024-03-08 15:15:00 +05:30
Neeraj Gupta
fe181fecbe Rename 2024-03-08 15:15:00 +05:30
Neeraj Gupta
50c3a7a8e5 Store resetSecret in encrypted form 2024-03-08 15:15:00 +05:30
Neeraj Gupta
f766484b2e Rename account_recovery -> two_factor_recovery 2024-03-08 15:15:00 +05:30
Neeraj Gupta
42e4364fda Add APIs to allow user to skip passkey based two-fa 2024-03-08 15:15:00 +05:30
Neeraj Gupta
09a7d557d2 Add API to get account two recovery status 2024-03-08 15:15:00 +05:30
Neeraj Gupta
13bae268ec Add models passkey reset via recoveryKey 2024-03-08 15:15:00 +05:30
Neeraj Gupta
23fcce245d Add table for account recovery 2024-03-08 15:15:00 +05:30
ashilkn
69c5d4f645 Added comment for context of line 2024-03-08 14:57:32 +05:30
Manav Rathi
d7854fa6c0 [web] Add nightly deployments of web projects (#746)
- Fix the branch name for the docs deployment
- Add web-nightly deployments
- Tweak the cron specification in existing workflows
2024-03-08 14:14:34 +05:30
ashilkn
cf8e684cb3 Revert "Remove unnecessary check"
This reverts commit a9631c09c8.
2024-03-08 14:09:43 +05:30
Manav Rathi
5d4486fce3 Add web-nightly and update existing 2024-03-08 14:09:41 +05:30
ashilkn
a9385f2132 Remove unnecessary mixin 2024-03-08 14:05:42 +05:30
Manav Rathi
37913ffbc7 Fix the branch name 2024-03-08 13:38:34 +05:30
Manav Rathi
215e89427d [WIP] [docs] Deploy docs (#742)
Add a GitHub workflow to deploy docs. If this works, will start using
this same approach for the other web apps in our repo.
2024-03-08 13:30:28 +05:30
Manav Rathi
2eb95ab215 Move the docs deployment to the new project, its final resting place 2024-03-08 13:26:41 +05:30
Manav Rathi
4b05dd49f6 [web] New translations (#739)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2024-03-08 13:16:22 +05:30
Manav Rathi
00f3a0ce90 [web] Document the need for yarn classic (#745)
People often run into issues with `yarn install` because they're using a
newer yarn. The situation is generally bad - we don't want to update to
Yarn v4 yet because it is marked experimental and is not the default
yarn that gets installed by node currently. We could add a
`packageManager` field to our package.json, but this will only fail the
build with a better (hopefully) error message, and will necessitate the
user to `corepack_enable`.

I'm not sure what's the best approach right now to make the initial
setup be seamless (I think we're using the approach that works for the
maximum of all the alternatives, but I'm not sure). At least, let me add
a note about it.

Ref:
* https://github.com/yarnpkg/berry/issues/5912
2024-03-08 13:15:28 +05:30
Manav Rathi
9e4f4c4670 Document the need for yarn classic 2024-03-08 13:11:04 +05:30
Manav Rathi
236d7e2f49 Fix the deploy workflow path 2024-03-08 13:03:50 +05:30
Manav Rathi
05d13979db Remove GitHub deployments
Not integrating GitHub deployments for now since creating a deployment
(anywhere) causes "This branch has not been deployed" message to appear on
unrelated branches.

Also, the Discord /github webhook doesn't support deployment status events
anyway - Discord accepts and responds to the webhook with a 204 but it doesn't
appear in the channel. This is not a big issue, we can easily massage the
payload ourselves, but just mentioning this for posterity. Refs:

* [Corresponding issue on Discord](https://github.com/discord/discord-api-docs/issues/6203#issuecomment-1608151265)

* [A general recipe](https://gist.github.com/jagrosh/5b1761213e33fc5b54ec7f6379034a22)

---

For deleting the existing deployment I had to

```
gh api /repos/ente-io/ente/deployments --jq=".[].id"
gh api --method DELETE -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" "/repos/ente-io/ente/deployments/1375794893"
```

This helpful hint taken from https://github.com/orgs/community/discussions/46375. Thanks!
2024-03-08 12:30:58 +05:30
ashilkn
454f5cdead Merge branch 'main' into fix_auto_scaling_on_loading_final_image 2024-03-08 12:17:04 +05:30
ashilkn
3f45345aad fix: when image is fully loaded after scaling the image, stay at the same position 2024-03-08 12:13:50 +05:30
ashilkn
8da57bd575 fix: auto scaling when final image is loaded case 2
When an image is magnified and a user is pressing down (onPressed) on the image, once the final image is loaded, the image auto scales
2024-03-08 12:09:33 +05:30
Manav Rathi
e47bcf2774 Merge for now 2024-03-08 12:05:12 +05:30
ashilkn
f14b499ffe fix: auto scaling after image is fully loaded after double tapping twice 2024-03-08 11:20:19 +05:30
Manav Rathi
4da96a3b76 Add the workflow 2024-03-08 11:19:04 +05:30
Manav Rathi
e3118ee7b0 Start adding notes 2024-03-08 10:37:40 +05:30
Manav Rathi
e3f2a77d2c Add workflow (sans the deployment)
Ref: https://vitepress.dev/reference/cli
2024-03-08 09:53:26 +05:30
Manav Rathi
10b5771445 Fix dead links 2024-03-08 09:48:49 +05:30
Crowdin Bot
835c6dea73 New Crowdin translations by GitHub Action 2024-03-08 00:09:25 +00:00
ashilkn
a9631c09c8 Remove unnecessary check
_loadedFinalImage will be true only after _loadedSmallThumbnail becomes true as first the small thumbnail is loaded and then the final image
2024-03-07 07:29:39 +05:30
ashilkn
c4ec818fb8 Remove unnecessary SingleTickerProviderStateMixin 2024-03-07 07:27:51 +05:30
ashilkn
d6fc57fc3f Merge branch 'main' into fix_auto_scaling 2024-03-06 19:09:27 +05:30
ashilkn
939e76d696 remove unnecessary mixin 2024-03-02 15:38:03 +05:30
339 changed files with 5942 additions and 4340 deletions

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
# Set line endings of shell scripts to LF, even on Windows, otherwise execution
# within Docker fails.
*.sh text eol=lf

View File

@@ -3,15 +3,16 @@ name: "Sync Crowdin translations (auth)"
on:
push:
paths:
# Run action when auth's intl_en.arb is changed
# Run workflow when auth's intl_en.arb is changed
- "mobile/lib/l10n/arb/app_en.arb"
# Or the workflow itself is changed
- ".github/workflows/auth-crowdin.yml"
branches: [main]
schedule:
# Run every 24 hours - https://crontab.guru/#0_*/24_*_*_*
- cron: "0 */24 * * *"
workflow_dispatch: # Allow manually running the action
# See: [Note: Run every 24 hours]
- cron: "50 1 * * *"
# Also allow manually running the workflow
workflow_dispatch:
jobs:
synchronize-with-crowdin:

View File

@@ -1,11 +1,9 @@
name: "Lint (auth)"
on:
# Run on every push to branches (this also covers pull requests)
# Run on every push to a branch other than main that changes auth/
push:
# See: [Note: Specify branch when specifying a path filter]
branches: ["**"]
# Only run if something changes in these paths
branches-ignore: [main]
paths:
- "auth/**"
- ".github/workflows/auth-lint.yml"

View File

@@ -49,6 +49,6 @@ jobs:
project_path: "./cli"
pre_command: export CGO_ENABLED=0
build_flags: "-trimpath"
ldflags: "-s -w"
ldflags: "-X main.AppVersion=${{ github.ref_name }} -s -w"
md5sum: false
sha256sum: true

47
.github/workflows/docs-deploy.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
name: "Deploy (docs)"
on:
# Run on every push to main that changes docs/
push:
branches: [main]
paths:
- "docs/**"
- ".github/workflows/docs-deploy.yml"
# Also allow manually running the workflow
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: docs
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"
- name: Install dependencies
run: yarn install
- name: Build production site
# Will create docs/.vitepress/dist
run: yarn build
- name: Publish
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: help
directory: docs/docs/.vitepress/dist
wranglerVersion: "3"

37
.github/workflows/docs-verify-build.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: "Verify build (docs)"
# Preflight build of docs. This allows us to ensure that yarn build is
# succeeding before we merge the PR into main.
on:
# Run on every push to a branch other than main that changes docs/
push:
branches-ignore: [main]
paths:
- "docs/**"
- ".github/workflows/docs-verify-build.yml"
jobs:
verify-build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: docs
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"
- name: Install dependencies
run: yarn install
- name: Build production site
run: yarn build

View File

@@ -3,15 +3,16 @@ name: "Sync Crowdin translations (mobile)"
on:
push:
paths:
# Run action when mobiles's intl_en.arb is changed
# Run workflow when mobiles's intl_en.arb is changed
- "mobile/lib/l10n/intl_en.arb"
# Or the workflow itself is changed
- ".github/workflows/mobile-crowdin.yml"
branches: [main]
schedule:
# Run every 24 hours - https://crontab.guru/#0_*/24_*_*_*
- cron: "0 */24 * * *"
workflow_dispatch: # Allow manually running the action
# See: [Note: Run every 24 hours]
- cron: "40 1 * * *"
# Also allow manually running the workflow
workflow_dispatch:
jobs:
synchronize-with-crowdin:

View File

@@ -1,11 +1,9 @@
name: "Lint (mobile)"
on:
# Run on every push (this also covers pull requests)
# Run on every push to a branch other than main that changes mobile/
push:
# See: [Note: Specify branch when specifying a path filter]
branches: ["**"]
# Only run if something changes in these paths
branches-ignore: [main]
paths:
- "mobile/**"
- ".github/workflows/mobile-lint.yml"

View File

@@ -39,7 +39,9 @@ jobs:
encodedString: ${{ secrets.SIGNING_KEY_PHOTOS }}
- name: Build independent APK
run: flutter build apk --release --flavor independent && mv build/app/outputs/flutter-apk/app-independent-release.apk build/app/outputs/flutter-apk/ente.apk
run: |
flutter build apk --release --flavor independent
mv build/app/outputs/flutter-apk/app-independent-release.apk build/app/outputs/flutter-apk/ente-${{ github.ref_name }}.apk
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_photos_key.jks"
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS_PHOTOS }}
@@ -52,5 +54,5 @@ jobs:
- name: Create a draft GitHub release
uses: ncipollo/release-action@v1
with:
artifacts: "mobile/build/app/outputs/flutter-apk/ente.apk,mobile/build/app/outputs/flutter-apk/sha256sum"
artifacts: "mobile/build/app/outputs/flutter-apk/ente-${{ github.ref_name }}.apk,mobile/build/app/outputs/flutter-apk/sha256sum"
draft: true

View File

@@ -1,11 +1,9 @@
name: "Lint (server)"
on:
# Run on every push (this also covers pull requests)
# Run on every push to a branch other than main that changes server/
push:
# See: [Note: Specify branch when specifying a path filter]
branches: ["**"]
# Only run if something changes in these paths
branches-ignore: [main]
paths:
- "server/**"
- ".github/workflows/server-lint.yml"

View File

@@ -3,15 +3,16 @@ name: "Sync Crowdin translations (web)"
on:
push:
paths:
# Run action when web's en-US/translation.json is changed
# Run workflow when web's en-US/translation.json is changed
- "web/apps/photos/public/locales/en-US/translation.json"
# Or the workflow itself is changed
- ".github/workflows/web-crowdin.yml"
branches: [main]
schedule:
# Run every 24 hours - https://crontab.guru/#0_*/24_*_*_*
- cron: "0 */24 * * *"
workflow_dispatch: # Allow manually running the action
# See: [Note: Run every 24 hours]
- cron: "20 1 * * *"
# Also allow manually running the workflow
workflow_dispatch:
jobs:
synchronize-with-crowdin:

View File

@@ -0,0 +1,43 @@
name: "Deploy (accounts)"
on:
push:
# Run workflow on pushes to the deploy/accounts
branches: [deploy/accounts]
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"
- name: Install dependencies
run: yarn install
- name: Build accounts
run: yarn build:accounts
- name: Publish accounts
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: deploy/accounts
directory: web/apps/accounts/out
wranglerVersion: "3"

43
.github/workflows/web-deploy-auth.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: "Deploy (auth)"
on:
push:
# Run workflow on pushes to the deploy/auth
branches: [deploy/auth]
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"
- name: Install dependencies
run: yarn install
- name: Build auth
run: yarn build:auth
- name: Publish auth
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: deploy/auth
directory: web/apps/auth/out
wranglerVersion: "3"

43
.github/workflows/web-deploy-cast.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: "Deploy (cast)"
on:
push:
# Run workflow on pushes to the deploy/cast
branches: [deploy/cast]
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"
- name: Install dependencies
run: yarn install
- name: Build cast
run: yarn build:cast
- name: Publish cast
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: deploy/cast
directory: web/apps/cast/out
wranglerVersion: "3"

43
.github/workflows/web-deploy-photos.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: "Deploy (photos)"
on:
push:
# Run workflow on pushes to the deploy/photos
branches: [deploy/photos]
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"
- name: Install dependencies
run: yarn install
- name: Build photos
run: yarn build:photos
- name: Publish photos
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: deploy/photos
directory: web/apps/photos/out
wranglerVersion: "3"

View File

@@ -1,20 +1,9 @@
name: "Lint (web)"
on:
# Run on every push (this also covers pull requests)
# Run on every push to a branch other than main that changes web/
push:
# [Note: Specify branch when specifying a path filter]
#
# Path filters are ignored for tag pushes, which causes this workflow to
# always run when we push a tag. Defining an explicit branch solves the
# issue. From GitHub's docs:
#
# > if you define both branches/branches-ignore and paths/paths-ignore,
# > the workflow will only run when both filters are satisfied.
#
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
branches: ["**"]
# Only run if something changes in these paths
branches-ignore: [main]
paths:
- "web/**"
- ".github/workflows/web-lint.yml"

94
.github/workflows/web-nightly.yml vendored Normal file
View File

@@ -0,0 +1,94 @@
name: "Nightly (web)"
on:
schedule:
# [Note: Run every 24 hours]
#
# Run every 24 hours - First field is minute, second is hour of the day
# This runs 23:15 UTC everyday - 1 and 15 are just arbitrary offset to
# avoid scheduling it on the exact hour, as suggested by GitHub.
#
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule
# https://crontab.guru/
#
- cron: "15 23 * * *"
# Also allow manually running the workflow
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"
- name: Install dependencies
run: yarn install
- name: Build accounts
run: yarn build:accounts
- name: Publish accounts
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: n-accounts
directory: web/apps/accounts/out
wranglerVersion: "3"
- name: Build auth
run: yarn build:auth
- name: Publish auth
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: n-auth
directory: web/apps/auth/out
wranglerVersion: "3"
- name: Build cast
run: yarn build:cast
- name: Publish cast
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: n-cast
directory: web/apps/cast/out
wranglerVersion: "3"
- name: Build photos
run: yarn build:photos
env:
NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT: https://albums.ente.sh
- name: Publish photos
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: n-photos
directory: web/apps/photos/out
wranglerVersion: "3"

52
.github/workflows/web-preview.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: "Preview (web)"
on:
workflow_dispatch:
inputs:
app:
description: "App to build and deploy"
type: choice
required: true
default: "photos"
options:
- "accounts"
- "auth"
- "cast"
- "photos"
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"
- name: Install dependencies
run: yarn install
- name: Build ${{ inputs.app }}
run: yarn build:${{ inputs.app }}
- name: Publish ${{ inputs.app }} to preview
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: preview
directory: web/apps/${{ inputs.app }}/out
wranglerVersion: "3"

4
.gitmodules vendored
View File

@@ -9,10 +9,6 @@
[submodule "auth/assets/simple-icons"]
path = auth/assets/simple-icons
url = https://github.com/simple-icons/simple-icons.git
[submodule "desktop/thirdparty/next-electron-server"]
path = desktop/thirdparty/next-electron-server
url = https://github.com/ente-io/next-electron-server.git
branch = desktop
[submodule "mobile/thirdparty/flutter"]
path = mobile/thirdparty/flutter
url = https://github.com/flutter/flutter.git

View File

@@ -50,13 +50,13 @@ Thank you for your support.
## Document
_Coming soon!_
The help guides and FAQs for users of Ente products are also open source, and
can be edited in a wiki-esque manner by our community members. More than the
quantity, we feel this helps improve the quality and approachability of the
documentation by bringing in more diverse viewpoints and familiarity levels.
See [docs/](docs/README.md) for how to edit these documents.
## Code contributions
If you'd like to contribute code, it is best to start small.

View File

@@ -70,7 +70,7 @@ existing users will be grandfathered in.
[<img height="42" src=".github/assets/app-store-badge.svg">](https://apps.apple.com/app/id6444121398)
[<img height="42" src=".github/assets/play-store-badge.png">](https://play.google.com/store/apps/details?id=io.ente.auth)
[<img height="42" src=".github/assets/f-droid-badge.png">](https://f-droid.org/packages/io.ente.auth/)
[<img height="42" src=".github/assets/github-badge.png">](https://github.com/ente-io/ente/releases?q=tag%3Av2.0.34&expanded=true)
[<img height="42" src=".github/assets/github-badge.png">](https://github.com/ente-io/ente/releases?q=tag%3Aauth-v2)
[<img height="42" src=".github/assets/web-badge.svg">](https://auth.ente.io)
</div>

View File

@@ -7,7 +7,7 @@ details as possible about whatever it is that you need help with, and we will
get back to you as soon as possible.
In some cases, your query might already have been answered in our help
documentation (_Coming soon!_).
documentation at [help.ente.io](https://help.ente.io).
Other ways to get in touch are:

View File

@@ -12,7 +12,7 @@ multi-device sync.
### Android
This repository's [GitHub
releases](https://github.com/ente-io/ente/releases/latest/download/ente-auth.apk)
releases](https://github.com/ente-io/ente/releases?q=tag%3Aauth-v2)
contains APKs, built straight from source. These builds keep themselves updated,
without relying on third party stores.

View File

@@ -37,8 +37,7 @@
{
"title": "BorgBase",
"altNames": ["borg"],
"slug": "BorgBase",
"hex": "222C31"
"slug": "BorgBase"
},
{
"title": "Brave Creators",
@@ -109,8 +108,7 @@
{
"title": "Gosuslugi",
"altNames": ["Госуслуги"],
"slug": "Gosuslugi",
"hex": "EE2F53"
"slug": "Gosuslugi"
},
{
"title": "Healthchecks.io",
@@ -127,13 +125,11 @@
},
{
"title": "IVPN",
"slug": "IVPN",
"hex": "FA3243"
"slug": "IVPN"
},
{
"title": "IceDrive",
"slug": "Icedrive",
"hex": "1F4FD0"
"slug": "Icedrive"
},
{
"title": "Jagex",
@@ -154,8 +150,7 @@
"title": "Kite"
},
{
"title": "Koofr",
"hex": "71BA05"
"title": "Koofr"
},
{
"title": "Kraken",
@@ -184,8 +179,7 @@
{
"title": "Murena",
"altNames": ["eCloud"],
"slug": "ecloud",
"hex": "EC6A55"
"slug": "ecloud"
},
{
"title": "Microsoft"
@@ -230,8 +224,7 @@
},
{
"title": "pCloud",
"slug": "pCloud",
"hex": "1EBCC5"
"slug": "pCloud"
},
{
"title": "Peerberry",
@@ -371,8 +364,7 @@
{
"title": "Yandex",
"altNames": ["Ya", "Яндекс"],
"slug": "Yandex",
"hex": "FC3F1D"
"slug": "Yandex"
}
]
}

View File

@@ -71,8 +71,6 @@ PODS:
- move_to_background (0.0.1):
- Flutter
- MTBBarcodeScanner (5.0.11)
- open_filex (0.0.2):
- Flutter
- OrderedSet (5.0.0)
- package_info_plus (0.4.5):
- Flutter
@@ -126,7 +124,6 @@ DEPENDENCIES:
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
- move_to_background (from `.symlinks/plugins/move_to_background/ios`)
- open_filex (from `.symlinks/plugins/open_filex/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- privacy_screen (from `.symlinks/plugins/privacy_screen/ios`)
@@ -183,8 +180,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/local_auth_ios/ios"
move_to_background:
:path: ".symlinks/plugins/move_to_background/ios"
open_filex:
:path: ".symlinks/plugins/open_filex/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
@@ -214,7 +209,7 @@ SPEC CHECKSUMS:
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
fk_user_agent: 1f47ec39291e8372b1d692b50084b0d54103c545
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_email_sender: 02d7443217d8c41483223627972bfdc09f74276b
flutter_inappwebview: acd4fc0f012cefd09015000c241137d82f01ba62
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
@@ -226,7 +221,6 @@ SPEC CHECKSUMS:
local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605
move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943

View File

@@ -167,7 +167,7 @@ class SuperLogging {
await setupLogDir();
}
if (sentryIsEnabled) {
await setupSentry();
setupSentry().ignore();
}
Logger.root.level = Level.ALL;
@@ -250,7 +250,7 @@ class SuperLogging {
// add error to sentry queue
if (sentryIsEnabled && rec.error != null) {
await _sendErrorToSentry(rec.error!, null);
_sendErrorToSentry(rec.error!, null).ignore();
}
}

View File

@@ -144,7 +144,8 @@
"enterCodeHint": "Enter the 6-digit code from\nyour authenticator app",
"lostDeviceTitle": "Lost device?",
"twoFactorAuthTitle": "Two-factor authentication",
"passkeyAuthTitle": "Passkey authentication",
"passkeyAuthTitle": "Passkey verification",
"verifyPasskey": "Verify passkey",
"recoverAccount": "Recover account",
"enterRecoveryKeyHint": "Enter your recovery key",
"recover": "Recover",
@@ -407,7 +408,7 @@
"hearUsWhereTitle": "How did you hear about Ente? (optional)",
"hearUsExplanation": "We don't track app installs. It'd help if you told us where you found us!",
"waitingForBrowserRequest": "Waiting for browser request...",
"launchPasskeyUrlAgain": "Launch passkey URL again",
"waitingForVerification": "Waiting for verification...",
"passkey": "Passkey",
"developerSettingsWarning":"Are you sure that you want to modify Developer settings?",
"developerSettings": "Developer settings",

View File

@@ -0,0 +1,13 @@
enum TwoFactorType { totp, passkey }
// ToString for TwoFactorType
String twoFactorTypeToString(TwoFactorType type) {
switch (type) {
case TwoFactorType.totp:
return "totp";
case TwoFactorType.passkey:
return "passkey";
default:
return type.name;
}
}

View File

@@ -17,6 +17,28 @@ class PasskeyService {
return response.data!["accountsToken"] as String;
}
Future<bool> isPasskeyRecoveryEnabled() async {
final response = await _enteDio.get(
"/users/two-factor/recovery-status",
);
return response.data!["isPasskeyRecoveryEnabled"] as bool;
}
Future<void> configurePasskeyRecovery(
String secret,
String userEncryptedSecret,
String userSecretNonce,
) async {
await _enteDio.post(
"/users/two-factor/passkeys/configure-recovery",
data: {
"secret": secret,
"userSecretCipher": userEncryptedSecret,
"userSecretNonce": userSecretNonce,
},
);
}
Future<void> openPasskeyPage(BuildContext context) async {
try {
final jwtToken = await getJwtToken();

View File

@@ -11,6 +11,7 @@ import 'package:ente_auth/core/event_bus.dart';
import 'package:ente_auth/core/network.dart';
import 'package:ente_auth/events/user_details_changed_event.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/account/two_factor.dart';
import 'package:ente_auth/models/api/user/srp.dart';
import 'package:ente_auth/models/delete_account.dart';
import 'package:ente_auth/models/key_attributes.dart';
@@ -762,7 +763,11 @@ class UserService {
}
}
Future<void> recoverTwoFactor(BuildContext context, String sessionID) async {
Future<void> recoverTwoFactor(
BuildContext context,
String sessionID,
TwoFactorType type,
) async {
final dialog = createProgressDialog(context, context.l10n.pleaseWait);
await dialog.show();
try {
@@ -770,6 +775,7 @@ class UserService {
_config.getHttpEndpoint() + "/users/two-factor/recover",
queryParameters: {
"sessionID": sessionID,
"twoFactorType": twoFactorTypeToString(type),
},
);
if (response.statusCode == 200) {
@@ -778,6 +784,7 @@ class UserService {
MaterialPageRoute(
builder: (BuildContext context) {
return TwoFactorRecoveryPage(
type,
sessionID,
response.data["encryptedSecret"],
response.data["secretDecryptionNonce"],
@@ -788,6 +795,7 @@ class UserService {
);
}
} on DioError catch (e) {
await dialog.hide();
_logger.severe(e);
if (e.response != null && e.response!.statusCode == 404) {
showToast(context, context.l10n.sessionExpired);
@@ -809,6 +817,7 @@ class UserService {
);
}
} catch (e) {
await dialog.hide();
_logger.severe(e);
// ignore: unawaited_futures
showErrorDialog(
@@ -823,6 +832,7 @@ class UserService {
Future<void> removeTwoFactor(
BuildContext context,
TwoFactorType type,
String sessionID,
String recoveryKey,
String encryptedSecret,
@@ -862,6 +872,7 @@ class UserService {
data: {
"sessionID": sessionID,
"secret": secret,
"twoFactorType": twoFactorTypeToString(type),
},
);
if (response.statusCode == 200) {
@@ -881,6 +892,7 @@ class UserService {
);
}
} on DioError catch (e) {
await dialog.hide();
_logger.severe(e);
if (e.response != null && e.response!.statusCode == 404) {
showToast(context, "Session expired");
@@ -902,6 +914,7 @@ class UserService {
);
}
} catch (e) {
await dialog.hide();
_logger.severe(e);
// ignore: unawaited_futures
showErrorDialog(

View File

@@ -1,9 +1,11 @@
import 'dart:convert';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/account/two_factor.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
import 'package:ente_auth/ui/components/models/button_type.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
@@ -99,30 +101,50 @@ class _PasskeyPageState extends State<PasskeyPage> {
}
Widget _getBody() {
final l10n = context.l10n;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
l10n.waitingForBrowserRequest,
style: const TextStyle(
height: 1.4,
fontSize: 16,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
context.l10n.waitingForVerification,
style: const TextStyle(
height: 1.4,
fontSize: 16,
),
),
),
const SizedBox(height: 16),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 32),
child: ElevatedButton(
style: Theme.of(context).colorScheme.optionalActionButtonStyle,
onPressed: launchPasskey,
child: Text(l10n.launchPasskeyUrlAgain),
const SizedBox(height: 16),
ButtonWidget(
buttonType: ButtonType.primary,
labelText: context.l10n.verifyPasskey,
onTap: () => launchPasskey(),
),
),
],
const Padding(padding: EdgeInsets.all(30)),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
UserService.instance.recoverTwoFactor(
context,
widget.sessionID,
TwoFactorType.passkey,
);
},
child: Container(
padding: const EdgeInsets.all(10),
child: Center(
child: Text(
context.l10n.recoverAccount,
style: const TextStyle(
decoration: TextDecoration.underline,
fontSize: 12,
),
),
),
),
),
],
),
),
);
}

View File

@@ -1,14 +1,7 @@
import 'dart:io';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/core/network.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/services/update_service.dart';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:open_filex/open_filex.dart';
import 'package:url_launcher/url_launcher_string.dart';
class AppUpdateDialog extends StatefulWidget {
@@ -114,116 +107,3 @@ class _AppUpdateDialogState extends State<AppUpdateDialog> {
);
}
}
class ApkDownloaderDialog extends StatefulWidget {
final LatestVersionInfo? versionInfo;
const ApkDownloaderDialog(this.versionInfo, {Key? key}) : super(key: key);
@override
State<ApkDownloaderDialog> createState() => _ApkDownloaderDialogState();
}
class _ApkDownloaderDialogState extends State<ApkDownloaderDialog> {
String? _saveUrl;
double? _downloadProgress;
@override
void initState() {
super.initState();
_saveUrl = Configuration.instance.getTempDirectory() +
"ente-" +
widget.versionInfo!.name! +
".apk";
_downloadApk();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
child: AlertDialog(
title: const Text(
"Downloading...",
style: TextStyle(
fontSize: 16,
),
textAlign: TextAlign.center,
),
content: LinearProgressIndicator(
value: _downloadProgress,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.alternativeColor,
),
),
),
);
}
Future<void> _downloadApk() async {
try {
if (!File(_saveUrl!).existsSync()) {
await Network.instance.getDio().download(
widget.versionInfo!.url!,
_saveUrl,
onReceiveProgress: (count, _) {
setState(() {
_downloadProgress = count / widget.versionInfo!.size!;
});
},
);
}
Navigator.of(context, rootNavigator: true).pop('dialog');
// ignore: unawaited_futures
OpenFilex.open(_saveUrl);
} catch (e) {
Logger("ApkDownloader").severe(e);
final AlertDialog alert = AlertDialog(
title: const Text("Sorry"),
content: const Text("The download could not be completed"),
actions: [
TextButton(
child: const Text(
"Ignore",
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop('dialog');
Navigator.of(context, rootNavigator: true).pop('dialog');
},
),
TextButton(
child: Text(
"Retry",
style: TextStyle(
color: Theme.of(context).colorScheme.alternativeColor,
),
),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop('dialog');
Navigator.of(context, rootNavigator: true).pop('dialog');
showDialog(
context: context,
builder: (BuildContext context) {
return ApkDownloaderDialog(widget.versionInfo);
},
barrierDismissible: false,
);
},
),
],
);
// ignore: unawaited_futures
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
barrierColor: Colors.black87,
);
return;
}
}
}

View File

@@ -21,6 +21,7 @@ import 'package:ente_auth/utils/dialog_util.dart';
import 'package:ente_auth/utils/navigation_util.dart';
import 'package:ente_auth/utils/toast_util.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
class SecuritySectionWidget extends StatefulWidget {
const SecuritySectionWidget({Key? key}) : super(key: key);
@@ -32,6 +33,7 @@ class SecuritySectionWidget extends StatefulWidget {
class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
final _config = Configuration.instance;
late bool _hasLoggedIn;
final Logger _logger = Logger('SecuritySectionWidget');
@override
void initState() {
@@ -75,7 +77,7 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
pressedColor: getEnteColorScheme(context).fillFaint,
trailingIcon: Icons.chevron_right_outlined,
trailingIconIsMuted: true,
onTap: () => PasskeyService.instance.openPasskeyPage(context),
onTap: () async => await onPasskeyClick(context),
),
sectionOptionSpacing,
MenuItemWidget(
@@ -159,6 +161,31 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
);
}
Future<void> onPasskeyClick(BuildContext buildContext) async {
try {
final isPassKeyResetEnabled =
await PasskeyService.instance.isPasskeyRecoveryEnabled();
if (!isPassKeyResetEnabled) {
final Uint8List recoveryKey = Configuration.instance.getRecoveryKey();
final resetKey = CryptoUtil.generateKey();
final resetKeyBase64 = CryptoUtil.bin2base64(resetKey);
final encryptionResult = CryptoUtil.encryptSync(
resetKey,
recoveryKey,
);
await PasskeyService.instance.configurePasskeyRecovery(
resetKeyBase64,
CryptoUtil.bin2base64(encryptionResult.encryptedData!),
CryptoUtil.bin2base64(encryptionResult.nonce!),
);
}
PasskeyService.instance.openPasskeyPage(buildContext).ignore();
} catch (e, s) {
_logger.severe("failed to open passkey page", e, s);
await showGenericErrorDialog(context: context);
}
}
Future<void> updateEmailMFA(bool enableEmailMFA) async {
try {
final UserDetails details =

View File

@@ -56,7 +56,8 @@ class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
text: context.l10n.unlock,
iconData: Icons.lock_open_outlined,
onTap: () async {
await _showLockScreen(source: "tapUnlock");
// ignore: unawaited_futures
_showLockScreen(source: "tapUnlock");
},
),
),

View File

@@ -1,4 +1,5 @@
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/account/two_factor.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/ui/lifecycle_event_handler.dart';
import 'package:flutter/material.dart';
@@ -129,7 +130,11 @@ class _TwoFactorAuthenticationPageState
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
UserService.instance.recoverTwoFactor(context, widget.sessionID);
UserService.instance.recoverTwoFactor(
context,
widget.sessionID,
TwoFactorType.totp,
);
},
child: Container(
padding: const EdgeInsets.all(10),

View File

@@ -1,6 +1,7 @@
import 'dart:ui';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/account/two_factor.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:flutter/material.dart';
@@ -9,8 +10,10 @@ class TwoFactorRecoveryPage extends StatefulWidget {
final String sessionID;
final String encryptedSecret;
final String secretDecryptionNonce;
final TwoFactorType type;
const TwoFactorRecoveryPage(
this.type,
this.sessionID,
this.encryptedSecret,
this.secretDecryptionNonce, {
@@ -72,6 +75,7 @@ class _TwoFactorRecoveryPageState extends State<TwoFactorRecoveryPage> {
? () async {
await UserService.instance.removeTwoFactor(
context,
widget.type,
widget.sessionID,
_recoveryKey.text,
widget.encryptedSecret,

View File

@@ -197,10 +197,10 @@ packages:
dependency: "direct main"
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.17.2"
computer:
dependency: "direct main"
description:
@@ -827,10 +827,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.9.1"
mime:
dependency: transitive
description:
@@ -879,14 +879,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.2"
open_filex:
dependency: "direct main"
description:
name: open_filex
sha256: "854aefd72dfd74219dc8c8d1767c34ec1eae64b8399a5be317bddb1ec2108915"
url: "https://pub.dev"
source: hosted
version: "4.3.2"
otp:
dependency: "direct main"
description:
@@ -1304,10 +1296,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.11.0"
step_progress_indicator:
dependency: "direct main"
description:
@@ -1320,10 +1312,10 @@ packages:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.1"
stream_transform:
dependency: transitive
description:
@@ -1368,26 +1360,26 @@ packages:
dependency: transitive
description:
name: test
sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f
sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46"
url: "https://pub.dev"
source: hosted
version: "1.24.9"
version: "1.24.3"
test_api:
dependency: transitive
description:
name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev"
source: hosted
version: "0.6.1"
version: "0.6.0"
test_core:
dependency: transitive
description:
name: test_core
sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a
sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e"
url: "https://pub.dev"
source: hosted
version: "0.5.9"
version: "0.5.3"
timezone:
dependency: transitive
description:
@@ -1576,10 +1568,10 @@ packages:
dependency: transitive
description:
name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.3.0"
version: "0.1.4-beta"
web_socket_channel:
dependency: transitive
description:
@@ -1637,5 +1629,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.2.0-194.0.dev <4.0.0"
dart: ">=3.1.0-185.0.dev <4.0.0"
flutter: ">=3.10.0"

View File

@@ -1,6 +1,6 @@
name: ente_auth
description: ente two-factor authenticator
version: 2.0.36+236
version: 2.0.42+242
publish_to: none
environment:
@@ -54,13 +54,11 @@ dependencies:
intl: ^0.18.0
json_annotation: ^4.5.0
local_auth: ^2.1.7
local_auth_android: ^1.0.31
local_auth_ios: ^1.1.3
logging: ^1.0.1
modal_bottom_sheet: ^3.0.0-pre
move_to_background: ^1.0.2
open_filex: ^4.3.2
otp: ^3.1.1
package_info_plus: ^4.1.0
password_strength: ^0.2.0

View File

@@ -64,7 +64,14 @@ ente account update --email email@domain.com --dir ~/photos
ente export
```
---
### CLI Docs
You can view more cli documents at [docs](docs/generated/ente.md).
To update the docs, run the following command:
```shell
go run main.go docs
```
## Docker

View File

@@ -62,7 +62,7 @@ var updateAccCmd = &cobra.Command{
fmt.Printf("invalid app. Accepted values are 'photos', 'locker', 'auth'")
}
err := ctrl.UpdateAccount(context.Background(), model.UpdateAccountParams{
err := ctrl.UpdateAccount(context.Background(), model.AccountCommandParams{
Email: email,
App: api.StringToApp(app),
ExportDir: &exportDir,
@@ -73,12 +73,49 @@ var updateAccCmd = &cobra.Command{
},
}
// Subcommand for 'account update'
var getTokenCmd = &cobra.Command{
Use: "get-token",
Short: "Get token for an account for a specific app",
Run: func(cmd *cobra.Command, args []string) {
recoverWithLog()
app, _ := cmd.Flags().GetString("app")
email, _ := cmd.Flags().GetString("email")
if email == "" {
fmt.Println("email must be specified, use --help for more information")
// print help
return
}
validApps := map[string]bool{
"photos": true,
"locker": true,
"auth": true,
}
if !validApps[app] {
fmt.Printf("invalid app. Accepted values are 'photos', 'locker', 'auth'")
}
err := ctrl.GetToken(context.Background(), model.AccountCommandParams{
Email: email,
App: api.StringToApp(app),
})
if err != nil {
fmt.Printf("Error updating account: %v\n", err)
}
},
}
func init() {
// Add 'config' subcommands to the root command
rootCmd.AddCommand(accountCmd)
// Add 'config' subcommands to the 'config' command
updateAccCmd.Flags().String("dir", "", "update export directory")
updateAccCmd.Flags().String("email", "", "email address of the account to update")
updateAccCmd.Flags().String("email", "", "email address of the account")
updateAccCmd.Flags().String("app", "photos", "Specify the app, default is 'photos'")
accountCmd.AddCommand(listAccCmd, addAccCmd, updateAccCmd)
getTokenCmd.Flags().String("email", "", "email address of the account")
getTokenCmd.Flags().String("app", "photos", "Specify the app, default is 'photos'")
accountCmd.AddCommand(listAccCmd, addAccCmd, updateAccCmd, getTokenCmd)
}

90
cli/cmd/admin.go Normal file
View File

@@ -0,0 +1,90 @@
package cmd
import (
"context"
"fmt"
"github.com/ente-io/cli/pkg/model"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"strings"
)
var _adminCmd = &cobra.Command{
Use: "admin",
Short: "Commands for admin actions",
Long: "Commands for admin actions like disable or enabling 2fa, bumping up the storage limit, etc.",
}
var _userDetailsCmd = &cobra.Command{
Use: "get-user-id",
Short: "Get user id",
RunE: func(cmd *cobra.Command, args []string) error {
recoverWithLog()
var flags = &model.AdminActionForUser{}
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if f.Name == "admin-user" {
flags.AdminEmail = f.Value.String()
}
if f.Name == "user" {
flags.UserEmail = f.Value.String()
}
})
return ctrl.GetUserId(context.Background(), *flags)
},
}
var _disable2faCmd = &cobra.Command{
Use: "disable-2fa",
Short: "Disable 2fa for a user",
RunE: func(cmd *cobra.Command, args []string) error {
recoverWithLog()
var flags = &model.AdminActionForUser{}
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if f.Name == "admin-user" {
flags.AdminEmail = f.Value.String()
}
if f.Name == "user" {
flags.UserEmail = f.Value.String()
}
})
fmt.Println("Not supported yet")
return nil
},
}
var _updateFreeUserStorage = &cobra.Command{
Use: "update-subscription",
Short: "Update subscription for the free user",
RunE: func(cmd *cobra.Command, args []string) error {
recoverWithLog()
var flags = &model.AdminActionForUser{}
noLimit := false
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if f.Name == "admin-user" {
flags.AdminEmail = f.Value.String()
}
if f.Name == "user" {
flags.UserEmail = f.Value.String()
}
if f.Name == "no-limit" {
noLimit = strings.ToLower(f.Value.String()) == "true"
}
})
return ctrl.UpdateFreeStorage(context.Background(), *flags, noLimit)
},
}
func init() {
rootCmd.AddCommand(_adminCmd)
_ = _userDetailsCmd.MarkFlagRequired("admin-user")
_ = _userDetailsCmd.MarkFlagRequired("user")
_userDetailsCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. (required)")
_userDetailsCmd.Flags().StringP("user", "u", "", "The email of the user to fetch details for. (required)")
_disable2faCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. (required)")
_disable2faCmd.Flags().StringP("user", "u", "", "The email of the user to disable 2FA for. (required)")
_updateFreeUserStorage.Flags().StringP("admin-user", "a", "", "The email of the admin user. (required)")
_updateFreeUserStorage.Flags().StringP("user", "u", "", "The email of the user to update subscription for. (required)")
// add a flag with no value --no-limit
_updateFreeUserStorage.Flags().String("no-limit", "True", "When true, sets 100TB as storage limit, and expiry to current date + 100 years")
_adminCmd.AddCommand(_userDetailsCmd, _disable2faCmd, _updateFreeUserStorage)
}

View File

@@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"github.com/ente-io/cli/pkg"
"github.com/spf13/cobra/doc"
"os"
"runtime"
@@ -11,7 +12,7 @@ import (
"github.com/spf13/cobra"
)
const AppVersion = "0.1.11"
var version string
var ctrl *pkg.ClICtrl
@@ -27,10 +28,15 @@ var rootCmd = &cobra.Command{
},
}
func GenerateDocs() error {
return doc.GenMarkdownTree(rootCmd, "./docs/generated")
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute(controller *pkg.ClICtrl) {
func Execute(controller *pkg.ClICtrl, ver string) {
ctrl = controller
version = ver
err := rootCmd.Execute()
if err != nil {
os.Exit(1)

View File

@@ -12,7 +12,7 @@ var versionCmd = &cobra.Command{
Short: "Prints the current version",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Version %s\n", AppVersion)
fmt.Printf("Version %s\n", version)
},
}

10
cli/config.yaml.example Normal file
View File

@@ -0,0 +1,10 @@
# You can put this configuration file in the following locations:
# - $HOME/.ente/config.yaml
# - config.yaml in the current working directory
# - $ENTE_CLI_CONFIG_PATH/config.yaml
endpoint:
api: "http://localhost:8080"
log:
http: false # log status code & time taken by requests

View File

@@ -0,0 +1,28 @@
## ente
CLI tool for exporting your photos from ente.io
### Synopsis
Start by creating a config file in your home directory:
```
ente [flags]
```
### Options
```
-h, --help help for ente
-t, --toggle Help message for toggle
```
### SEE ALSO
* [ente account](ente_account.md) - Manage account settings
* [ente admin](ente_admin.md) - Commands for admin actions
* [ente auth](ente_auth.md) - Authenticator commands
* [ente export](ente_export.md) - Starts the export process
* [ente version](ente_version.md) - Prints the current version
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,19 @@
## ente account
Manage account settings
### Options
```
-h, --help help for account
```
### SEE ALSO
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
* [ente account add](ente_account_add.md) - Add a new account
* [ente account get-token](ente_account_get-token.md) - Get token for an account for a specific app
* [ente account list](ente_account_list.md) - list configured accounts
* [ente account update](ente_account_update.md) - Update an existing account's export directory
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,19 @@
## ente account add
Add a new account
```
ente account add [flags]
```
### Options
```
-h, --help help for add
```
### SEE ALSO
* [ente account](ente_account.md) - Manage account settings
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,21 @@
## ente account get-token
Get token for an account for a specific app
```
ente account get-token [flags]
```
### Options
```
--app string Specify the app, default is 'photos' (default "photos")
--email string email address of the account
-h, --help help for get-token
```
### SEE ALSO
* [ente account](ente_account.md) - Manage account settings
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,19 @@
## ente account list
list configured accounts
```
ente account list [flags]
```
### Options
```
-h, --help help for list
```
### SEE ALSO
* [ente account](ente_account.md) - Manage account settings
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,22 @@
## ente account update
Update an existing account's export directory
```
ente account update [flags]
```
### Options
```
--app string Specify the app, default is 'photos' (default "photos")
--dir string update export directory
--email string email address of the account
-h, --help help for update
```
### SEE ALSO
* [ente account](ente_account.md) - Manage account settings
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,22 @@
## ente admin
Commands for admin actions
### Synopsis
Commands for admin actions like disable or enabling 2fa, bumping up the storage limit, etc.
### Options
```
-h, --help help for admin
```
### SEE ALSO
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
* [ente admin disable-2fa](ente_admin_disable-2fa.md) - Disable 2fa for a user
* [ente admin get-user-id](ente_admin_get-user-id.md) - Get user id
* [ente admin update-subscription](ente_admin_update-subscription.md) - Update subscription for the free user
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,21 @@
## ente admin disable-2fa
Disable 2fa for a user
```
ente admin disable-2fa [flags]
```
### Options
```
-a, --admin-user string The email of the admin user. (required)
-h, --help help for disable-2fa
-u, --user string The email of the user to disable 2FA for. (required)
```
### SEE ALSO
* [ente admin](ente_admin.md) - Commands for admin actions
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,21 @@
## ente admin get-user-id
Get user id
```
ente admin get-user-id [flags]
```
### Options
```
-a, --admin-user string The email of the admin user. (required)
-h, --help help for get-user-id
-u, --user string The email of the user to fetch details for. (required)
```
### SEE ALSO
* [ente admin](ente_admin.md) - Commands for admin actions
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,22 @@
## ente admin update-subscription
Update subscription for the free user
```
ente admin update-subscription [flags]
```
### Options
```
-a, --admin-user string The email of the admin user. (required)
-h, --help help for update-subscription
--no-limit string When true, sets 100TB as storage limit, and expiry to current date + 100 years (default "True")
-u, --user string The email of the user to update subscription for. (required)
```
### SEE ALSO
* [ente admin](ente_admin.md) - Commands for admin actions
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,16 @@
## ente auth
Authenticator commands
### Options
```
-h, --help help for auth
```
### SEE ALSO
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
* [ente auth decrypt](ente_auth_decrypt.md) - Decrypt authenticator export
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,19 @@
## ente auth decrypt
Decrypt authenticator export
```
ente auth decrypt [input] [output] [flags]
```
### Options
```
-h, --help help for decrypt
```
### SEE ALSO
* [ente auth](ente_auth.md) - Authenticator commands
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,19 @@
## ente export
Starts the export process
```
ente export [flags]
```
### Options
```
-h, --help help for export
```
### SEE ALSO
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
###### Auto generated by spf13/cobra on 13-Mar-2024

View File

@@ -0,0 +1,19 @@
## ente version
Prints the current version
```
ente version [flags]
```
### Options
```
-h, --help help for version
```
### SEE ALSO
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
###### Auto generated by spf13/cobra on 13-Mar-2024

27
cli/docs/selfhost.md Normal file
View File

@@ -0,0 +1,27 @@
## Self Hosting
If you are self-hosting the server, you can still configure CLI to export data & perform basic admin actions.
To do this, first configure the CLI to point to your server.
Define a config.yaml and put it either in the same directory as CLI binary or path defined in env variable `ENTE_CLI_CONFIG_PATH`
```yaml
endpoint:
api: "http://localhost:8080"
```
You should be able to [add an account](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_account_add.md), and subsequently increase the [storage and account validity](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_admin_update-subscription.md) using the CLI.
For the admin actions, you first need to whitelist admin users. You can create `server/museum.yaml`, and whitelist add the admin userID `internal.admins`. See [local.yaml](https://github.com/ente-io/ente/blob/main/server/configurations/local.yaml#L211C1-L232C1) in the server source code for details about how to define this.
You can use [account list](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_account_list.md) command to find the user id of any account.
```yaml
# ....
internal:
admins:
# - 1580559962386440
# ....
```

View File

@@ -12,10 +12,12 @@ require (
require (
github.com/alessio/shellescape v1.4.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/danieljoos/wincred v1.2.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
)
require (

View File

@@ -48,6 +48,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec=
@@ -168,6 +169,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=

57
cli/internal/api/admin.go Normal file
View File

@@ -0,0 +1,57 @@
package api
import (
"context"
"fmt"
"github.com/ente-io/cli/internal/api/models"
"time"
)
func (c *Client) GetUserIdFromEmail(ctx context.Context, email string) (*models.UserDetails, error) {
var res models.UserDetails
r, err := c.restClient.R().
SetContext(ctx).
SetResult(&res).
SetQueryParam("email", email).
Get("/admin/user/")
if err != nil {
return nil, err
}
if r.IsError() {
return nil, &ApiError{
StatusCode: r.StatusCode(),
Message: r.String(),
}
}
return &res, nil
}
func (c *Client) UpdateFreePlanSub(ctx context.Context, userDetails *models.UserDetails, storageInBytes int64, expiryTimeInMicro int64) error {
var res interface{}
if userDetails.Subscription.ProductID != "free" {
return fmt.Errorf("user is not on free plan")
}
payload := map[string]interface{}{
"userID": userDetails.User.ID,
"expiryTime": expiryTimeInMicro,
"transactionID": fmt.Sprintf("cli-on-%d", time.Now().Unix()),
"productID": "free",
"paymentProvider": "",
"storage": storageInBytes,
}
r, err := c.restClient.R().
SetContext(ctx).
SetResult(&res).
SetBody(payload).
Put("/admin/user/subscription")
if err != nil {
return err
}
if r.IsError() {
return &ApiError{
StatusCode: r.StatusCode(),
Message: r.String(),
}
}
return nil
}

View File

@@ -2,19 +2,30 @@ package api
import (
"context"
"github.com/ente-io/cli/utils/constants"
"github.com/spf13/viper"
"strconv"
"strings"
)
var (
downloadHost = "https://files.ente.io/?fileID="
)
func downloadUrl(fileID int64) string {
apiEndpoint := viper.GetString("endpoint.api")
if apiEndpoint == "" || strings.Compare(apiEndpoint, constants.EnteApiUrl) == 0 {
return downloadHost + strconv.FormatInt(fileID, 10)
}
return apiEndpoint + "/files/download/" + strconv.FormatInt(fileID, 10)
}
func (c *Client) DownloadFile(ctx context.Context, fileID int64, absolutePath string) error {
req := c.downloadClient.R().
SetContext(ctx).
SetOutput(absolutePath)
attachToken(req)
r, err := req.Get(downloadHost + strconv.FormatInt(fileID, 10))
r, err := req.Get(downloadUrl(fileID))
if r.IsError() {
return &ApiError{
StatusCode: r.StatusCode(),

View File

@@ -30,6 +30,16 @@ func logRequest(req *resty.Request) {
}
}
}
// log query params if present
if len(req.QueryParam) > 0 {
fmt.Println(color.GreenString("Query Params:"))
for k, v := range req.QueryParam {
if k == TokenQuery {
v = []string{"REDACTED"}
}
fmt.Printf("%s: %s\n", color.CyanString(k), color.YellowString(strings.Join(v, ",")))
}
}
}
func logResponse(resp *resty.Response) {

View File

@@ -0,0 +1,16 @@
package models
type UserDetails struct {
User struct {
ID int64 `json:"id"`
} `json:"user"`
Usage int64 `json:"usage"`
Email string `json:"email"`
Subscription struct {
ExpiryTime int64 `json:"expiryTime"`
Storage int64 `json:"storage"`
ProductID string `json:"productID"`
PaymentProvider string `json:"paymentProvider"`
} `json:"subscription"`
}

View File

@@ -5,11 +5,12 @@ import (
"errors"
"fmt"
"github.com/ente-io/cli/internal/api"
"golang.org/x/term"
"log"
"os"
"regexp"
"strconv"
"strings"
"golang.org/x/term"
)
func GetSensitiveField(label string) (string, error) {
@@ -81,6 +82,79 @@ func GetCode(promptText string, length int) (string, error) {
}
}
// parseStorageSize parses a string representing a storage size (e.g., "500MB", "2GB") into bytes.
func parseStorageSize(input string) (int64, error) {
units := map[string]int64{
"MB": 1 << 20,
"GB": 1 << 30,
"TB": 1 << 40,
}
re := regexp.MustCompile(`(?i)^(\d+(?:\.\d+)?)(MB|GB|TB)$`)
matches := re.FindStringSubmatch(input)
if matches == nil {
return 0, errors.New("invalid format")
}
number, err := strconv.ParseFloat(matches[1], 64)
if err != nil {
return 0, fmt.Errorf("invalid number: %s", matches[1])
}
unit := strings.ToUpper(matches[2])
bytes := int64(number * float64(units[unit]))
return bytes, nil
}
func ConfirmAction(promptText string) (bool, error) {
for {
input, err := GetUserInput(promptText)
if err != nil {
return false, err
}
if input == "" {
log.Fatal("No input entered")
return false, errors.New("invalid input. Please enter 'y' or 'n'")
}
if input == "c" {
return false, errors.New("cancelled")
}
if input == "y" {
return true, nil
}
if input == "n" {
return false, nil
}
fmt.Println("Invalid input. Please enter 'y' or 'n'.")
}
}
// GetStorageSize prompts the user for a storage size and returns the size in bytes.
func GetStorageSize(promptText string) (int64, error) {
for {
input, err := GetUserInput(promptText)
if err != nil {
return 0, err
}
if input == "" {
log.Fatal("No storage size entered")
return 0, errors.New("no storage size entered")
}
if input == "c" {
return 0, errors.New("storage size entry cancelled")
}
bytes, err := parseStorageSize(input)
if err != nil {
fmt.Println("Invalid storage size format. Please use a valid format like '500MB', '2GB'.")
continue
}
return bytes, nil
}
}
func GetExportDir() string {
for {
exportDir, err := GetUserInput("Enter export directory")

View File

@@ -8,12 +8,15 @@ import (
"github.com/ente-io/cli/pkg"
"github.com/ente-io/cli/pkg/secrets"
"github.com/ente-io/cli/utils/constants"
"github.com/spf13/viper"
"log"
"os"
"path/filepath"
"strings"
)
var AppVersion = "0.1.12"
func main() {
cliDBPath, err := GetCLIConfigPath()
if secrets.IsRunningInContainer() {
@@ -23,10 +26,10 @@ func main() {
log.Fatalf("Please mount a volume to %s to persist cli data\n%v\n", cliDBPath, err)
}
}
if err != nil {
log.Fatalf("Could not create cli config path\n%v\n", err)
}
initConfig(cliDBPath)
newCliPath := fmt.Sprintf("%s/ente-cli.db", cliDBPath)
if !strings.HasPrefix(cliDBPath, "/") {
oldCliPath := fmt.Sprintf("%sente-cli.db", cliDBPath)
@@ -48,8 +51,8 @@ func main() {
}
ctrl := pkg.ClICtrl{
Client: api.NewClient(api.Params{
Debug: false,
//Host: "http://localhost:8080",
Debug: viper.GetBool("log.http"),
Host: viper.GetString("endpoint.api"),
}),
DB: db,
KeyHolder: secrets.NewKeyHolder(secrets.GetOrCreateClISecret()),
@@ -63,7 +66,32 @@ func main() {
panic(err)
}
}()
cmd.Execute(&ctrl)
if len(os.Args) == 2 && os.Args[1] == "docs" {
log.Println("Generating docs")
err = cmd.GenerateDocs()
if err != nil {
log.Fatal(err)
}
return
}
cmd.Execute(&ctrl, AppVersion)
}
func initConfig(cliConfigPath string) {
viper.SetConfigName("config") // name of config file (without extension)
viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
viper.AddConfigPath(cliConfigPath + "/") // path to look for the config file in
viper.AddConfigPath(".") // optionally look for config in the working directory
viper.SetDefault("endpoint.api", constants.EnteApiUrl)
viper.SetDefault("log.http", false)
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
} else {
// Config file was found but another error was produced
}
}
}
// GetCLIConfigPath returns the path to the .ente-cli folder and creates it if it doesn't exist.

View File

@@ -142,7 +142,7 @@ func (c *ClICtrl) ListAccounts(cxt context.Context) error {
return nil
}
func (c *ClICtrl) UpdateAccount(ctx context.Context, params model.UpdateAccountParams) error {
func (c *ClICtrl) UpdateAccount(ctx context.Context, params model.AccountCommandParams) error {
accounts, err := c.GetAccounts(ctx)
if err != nil {
return err
@@ -177,5 +177,27 @@ func (c *ClICtrl) UpdateAccount(ctx context.Context, params model.UpdateAccountP
return b.Put([]byte(accountKey), accInfoBytes)
})
return err
}
func (c *ClICtrl) GetToken(ctx context.Context, params model.AccountCommandParams) error {
accounts, err := c.GetAccounts(ctx)
if err != nil {
return err
}
var acc *model.Account
for _, a := range accounts {
if a.Email == params.Email && a.App == params.App {
acc = &a
break
}
}
if acc == nil {
return fmt.Errorf("account not found, use `account list` to list accounts")
}
secretInfo, err := c.KeyHolder.LoadSecrets(*acc)
if err != nil {
return err
}
fmt.Println(secretInfo.TokenStr())
return nil
}

114
cli/pkg/admin_actions.go Normal file
View File

@@ -0,0 +1,114 @@
package pkg
import (
"context"
"fmt"
"github.com/ente-io/cli/internal"
"github.com/ente-io/cli/pkg/model"
"github.com/ente-io/cli/utils"
"log"
"strings"
"time"
)
func (c *ClICtrl) GetUserId(ctx context.Context, params model.AdminActionForUser) error {
accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail)
if err != nil {
return err
}
id, err := c.Client.GetUserIdFromEmail(accountCtx, params.UserEmail)
if err != nil {
return err
}
fmt.Println(id.User.ID)
return nil
}
func (c *ClICtrl) UpdateFreeStorage(ctx context.Context, params model.AdminActionForUser, noLimit bool) error {
accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail)
if err != nil {
return err
}
userDetails, err := c.Client.GetUserIdFromEmail(accountCtx, params.UserEmail)
if err != nil {
return err
}
if noLimit {
// set storage to 100TB and expiry to + 100 years
err := c.Client.UpdateFreePlanSub(accountCtx, userDetails, 100*1024*1024*1024*1024, time.Now().AddDate(100, 0, 0).UnixMicro())
if err != nil {
return err
} else {
fmt.Println("Successfully updated storage and expiry date for user")
}
return nil
}
storageSize, err := internal.GetStorageSize("Enter a storage size (e.g.'5MB', '10GB', '2Tb'): ")
if err != nil {
log.Fatalf("Error: %v", err)
}
dateStr, err := internal.GetUserInput("Enter sub expiry date in YYYY-MM-DD format (e.g.'2040-12-31')")
if err != nil {
log.Fatalf("Error: %v", err)
}
date, err := _parseDateOrDateTime(dateStr)
if err != nil {
return err
}
fmt.Printf("Updating storage for user %s to %s (old %s) with new expirty %s (old %s) \n",
params.UserEmail,
utils.ByteCountDecimalGIB(storageSize), utils.ByteCountDecimalGIB(userDetails.Subscription.Storage),
date.Format("2006-01-02"),
time.UnixMicro(userDetails.Subscription.ExpiryTime).Format("2006-01-02"))
// press y to confirm
confirmed, _ := internal.ConfirmAction("Are you sure you want to update the storage ('y' or 'n')?")
if !confirmed {
return nil
} else {
err := c.Client.UpdateFreePlanSub(accountCtx, userDetails, storageSize, date.UnixMicro())
if err != nil {
return err
} else {
fmt.Println("Successfully updated storage and expiry date for user")
}
}
return nil
}
func (c *ClICtrl) buildAdminContext(ctx context.Context, adminEmail string) (context.Context, error) {
accounts, err := c.GetAccounts(ctx)
if err != nil {
return nil, err
}
var acc *model.Account
for _, a := range accounts {
if a.Email == adminEmail {
acc = &a
break
}
}
if acc == nil {
return nil, fmt.Errorf("account not found for %s, use `account list` to list accounts", adminEmail)
}
secretInfo, err := c.KeyHolder.LoadSecrets(*acc)
if err != nil {
return nil, err
}
accountCtx := c.buildRequestContext(ctx, *acc)
c.Client.AddToken(acc.AccountKey(), secretInfo.TokenStr())
return accountCtx, nil
}
func _parseDateOrDateTime(input string) (time.Time, error) {
var layout string
if strings.Contains(input, " ") {
// If the input contains a space, assume it's a date-time format
layout = "2006-01-02 15:04:05"
} else {
// If there's no space, assume it's just a date
layout = "2006-01-02"
}
return time.Parse(layout, input)
}

View File

@@ -1,6 +1,7 @@
package model
import (
"encoding/base64"
"fmt"
"github.com/ente-io/cli/internal/api"
)
@@ -17,7 +18,7 @@ type Account struct {
ExportDir string `json:"exportDir"`
}
type UpdateAccountParams struct {
type AccountCommandParams struct {
Email string
App api.App
ExportDir *string
@@ -37,3 +38,7 @@ type AccSecretInfo struct {
Token []byte
PublicKey []byte
}
func (a *AccSecretInfo) TokenStr() string {
return base64.URLEncoding.EncodeToString(a.Token)
}

6
cli/pkg/model/admin.go Normal file
View File

@@ -0,0 +1,6 @@
package model
type AdminActionForUser struct {
UserEmail string
AdminEmail string
}

View File

@@ -1,5 +1,16 @@
#!/bin/bash
# Fetch the latest tag that starts with "cli-"
# shellcheck disable=SC2046
# shellcheck disable=SC2006
LATEST_TAG=$(git describe --tags `git rev-list --tags='cli-*' --max-count=1`)
# Check if the LATEST_TAG variable is empty
if [ -z "$LATEST_TAG" ]; then
echo "No 'cli-' tag found. Exiting..."
exit 1
fi
VERSION=${LATEST_TAG#cli-}
# Create a "bin" directory if it doesn't exist
mkdir -p bin
@@ -29,7 +40,7 @@ do
fi
# Build the binary and place it in the "bin" directory
go build -ldflags="-s -w" -trimpath -o "bin/$BINARY_NAME" main.go
go build -ldflags="-X main.AppVersion=${VERSION} -s -w" -trimpath -o "bin/$BINARY_NAME" main.go
# Print a message indicating the build is complete for the current OS and architecture
echo "Built for $OS ($ARCH) as bin/$BINARY_NAME"

View File

@@ -1,3 +1,4 @@
package constants
const CliDataPath = "/cli-data/"
const EnteApiUrl = "https://api.ente.io"

31
cli/utils/convert.go Normal file
View File

@@ -0,0 +1,31 @@
package utils
import (
"fmt"
)
func ByteCountDecimal(b int64) string {
const unit = 1000
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
}
func ByteCountDecimalGIB(b int64) string {
const unit = 1024
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
}

View File

@@ -1,7 +1,6 @@
package utils
import (
"fmt"
"log"
"time"
)
@@ -10,16 +9,3 @@ func TimeTrack(start time.Time, name string) {
elapsed := time.Since(start)
log.Printf("%s took %s", name, elapsed)
}
func ByteCountDecimal(b int64) string {
const unit = 1000
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
}

View File

@@ -52,7 +52,4 @@ jobs:
# macOS notarization API key
API_KEY_ID: ${{ secrets.api_key_id }}
API_KEY_ISSUER_ID: ${{ secrets.api_key_issuer_id}}
# setry crash reporting token
SENTRY_AUTH_TOKEN: ${{secrets.sentry_auth_token}}
NEXT_PUBLIC_DISABLE_SENTRY: ${{secrets.next_public_disable_sentry}}
USE_HARD_LINKS: false

29
desktop/.gitignore vendored
View File

@@ -1,12 +1,21 @@
node_modules
app
.next/
dist
.vscode
buildingSteps.md
# Node
node_modules/
# macOS
.DS_Store
.idea/
build/.DS_Store
# Editors
.vscode/
# Local env files
.env
.electron-symbols/
models/
.env.*.local
# tsc transpiles src/**/*.ts and emits the generated JS into app
app/
# out is a symlink to the photos web app's dir
out
# electron-builder
dist/

View File

@@ -1,11 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
branch="$(git rev-parse --abbrev-ref HEAD)"
if [ "$branch" = "main" ]; then
echo "You can't commit directly to main branch"
exit 1
fi
npx lint-staged

View File

@@ -1,6 +1,7 @@
{
"tabWidth": 4,
"trailingComma": "es5",
"singleQuote": true,
"bracketSameLine": true
}
"plugins": [
"prettier-plugin-organize-imports",
"prettier-plugin-packagejson"
]
}

View File

@@ -1 +0,0 @@
network-timeout 500000

View File

@@ -4,128 +4,128 @@
### New
- Option to select file download location.
- Add support for searching popular cities
- Sorted duplicates in desecending order of size
- Add Counter to upload section
- Display full name and collection name on hover on dedupe screen photos
- Option to select file download location.
- Add support for searching popular cities
- Sorted duplicates in desecending order of size
- Add Counter to upload section
- Display full name and collection name on hover on dedupe screen photos
### Bug Fixes
- Fix add to album padding issue
- Fix double uncategorized album issue
- Hide Hidden collection files from all section
- Fix add to album padding issue
- Fix double uncategorized album issue
- Hide Hidden collection files from all section
## v1.6.62
### New
- Integrated onnx clip runner
- Integrated onnx clip runner
### Bug Fixes
- Fixes login button requiring double click issue
- Fixes Collection sort state not preserved issue
- Fixes continuous export causing app crash
- Improves ML related copies for better distinction from clip
- Added Better favicon for light mode
- Fixed face indexing issues
- Fixed thumbnail load issue
- Fixes login button requiring double click issue
- Fixes Collection sort state not preserved issue
- Fixes continuous export causing app crash
- Improves ML related copies for better distinction from clip
- Added Better favicon for light mode
- Fixed face indexing issues
- Fixed thumbnail load issue
## v1.6.60
### Bug Fixes
- Fix Thumbnail Orientation issue
- Fix ML logging issue
- Fix Thumbnail Orientation issue
- Fix ML logging issue
## v1.6.59
### New
- Added arm64 builds for linux
- Added arm64 builds for linux
### Bug Fixes
- Fix Editor file not loading issue
- Fix ML results missing thumbnail issue
- Fix Editor file not loading issue
- Fix ML results missing thumbnail issue
## v1.6.58
### Bug Fixes
- Fix File load issue
- Fix File load issue
## v1.6.57
### New Features
- Added encrypted Disk caching for files
- Added option to customize cache folder location
- Added encrypted Disk caching for files
- Added option to customize cache folder location
### Bug Fixes
- Fixed caching issue,causing multiple download of file during ml sync
- Fixed caching issue,causing multiple download of file during ml sync
## v1.6.55
### Bug Fixes
- Added manage family portal option if add-on is active
- Fixed filename date parsing issue
- Fixed storage limit ui glitch
- Fixed dedupe page layout issue
- Fixed ElectronAPI refactoring issue
- Fixed Search related issues
- Added manage family portal option if add-on is active
- Fixed filename date parsing issue
- Fixed storage limit ui glitch
- Fixed dedupe page layout issue
- Fixed ElectronAPI refactoring issue
- Fixed Search related issues
## v1.6.54
### New Features
- Added support for HEIC and raw image in photo editor
- Added support for HEIC and raw image in photo editor
### Bug Fixes
- Fixed 16bit HDR HEIC images support
- Fixed blocked login due safe storage issue
- Fixed Search related issues
- Fixed issue of watch folder not cleared on logout
- other under the hood ui/ux improvements
- Fixed 16bit HDR HEIC images support
- Fixed blocked login due safe storage issue
- Fixed Search related issues
- Fixed issue of watch folder not cleared on logout
- other under the hood ui/ux improvements
## v1.6.53
### Bug Fixes
- Fixed watch folder disabled issue
- Fixed BF Add on related issues
- Fixed clip sync issue and added better logging
- Fixed mov file upload
- Fixed clip extraction related issue
- Fixed watch folder disabled issue
- Fixed BF Add on related issues
- Fixed clip sync issue and added better logging
- Fixed mov file upload
- Fixed clip extraction related issue
## v1.6.52
### New Features
- Added Clip Desktop on windows
- Added Clip Desktop on windows
### Bug Fixes
- fixed google json matching issue
- other under-the-hood changes to improve performance and bug fixes
- fixed google json matching issue
- other under-the-hood changes to improve performance and bug fixes
## v1.6.50
### New Features
- Added Clip desktop
- Added Clip desktop
### Bug Fixes
- Fixed desktop downloaded file had extra dot in the name
- Cleanup error messages
- fix the motion photo clustering issue
- Add option to disable cf proxy locally
- other under-the-hood changes to improve UX
- Fixed desktop downloaded file had extra dot in the name
- Cleanup error messages
- fix the motion photo clustering issue
- Add option to disable cf proxy locally
- other under-the-hood changes to improve UX
## v1.6.49
@@ -137,54 +137,54 @@ Check out our [blog](https://ente.io/blog/introducing-web-desktop-photo-editor/)
### Bug Fixes
- Fixed misaligned icons in photo-viewer
- Fixed issue with Motion photo upload
- Fixed issue with Live-photo upload
- other minor ux improvement
- Fixed misaligned icons in photo-viewer
- Fixed issue with Motion photo upload
- Fixed issue with Live-photo upload
- other minor ux improvement
## v1.6.46
### Bug Fixes
- Fixes OOM crashes during file upload [#1379](https://github.com/ente-io/photos-web/pull/1379)
- Fixes OOM crashes during file upload [#1379](https://github.com/ente-io/photos-web/pull/1379)
## v1.6.45
### Bug Fixes
- Fixed app keeps reloading issue [#235](https://github.com/ente-io/photos-desktop/pull/235)
- Fixed dng and arw preview issue [#1378](https://github.com/ente-io/photos-web/pull/1378)
- Added view crash report option (help menu) for user to share electron crash report locally
- Fixed app keeps reloading issue [#235](https://github.com/ente-io/photos-desktop/pull/235)
- Fixed dng and arw preview issue [#1378](https://github.com/ente-io/photos-web/pull/1378)
- Added view crash report option (help menu) for user to share electron crash report locally
## v1.6.44
- Upgraded electron to get latest security patches and other improvements.
- Upgraded electron to get latest security patches and other improvements.
## v1.6.43
### Added
- #### Check for update and changelog option
- #### Check for update and changelog option
Added options to check for update manually and a view changelog via the app menubar
- #### Opt out of crash reporting
- #### Opt out of crash reporting
Added option to out of a crash reporting, it can accessed from the settings -> preferences -> disable crash reporting
- #### Type search
- #### Type search
Added new search option to search files based on file type i.e, image, video, live-photo.
- #### Manual Convert Button
- #### Manual Convert Button
In case the video is not playable, Now there is a convert button which can be used to trigger conversion of the video to supported format.
- #### File Download Progress
- #### File Download Progress
The file loader now also shows the exact percentage download progress, instead of just a simple loader.
- #### Bug fixes & other enhancements
- #### Bug fixes & other enhancements
We have squashed a few pesky bugs that were reported by our community
@@ -192,21 +192,21 @@ Check out our [blog](https://ente.io/blog/introducing-web-desktop-photo-editor/)
### Added
- #### Hidden albums
- #### Hidden albums
You can now hide albums, just like individual memories.
- #### Email verification
- #### Email verification
We have now made email verification optional, so you can sign in with just your email address and password, without waiting for a verification code.
You can opt in / out of email verification from Settings > Security.
- #### Download Album
- #### Download Album
You can now chose the download location for downloading albums. Along with that we have also added progress bar for album download.
- #### Bug fixes & other enhancements
- #### Bug fixes & other enhancements
We have squashed a few pesky bugs that were reported by our community

View File

@@ -10,33 +10,28 @@ To know more about Ente, see [our main README](../README.md) or visit
## Building from source
> [!CAUTION]
>
> We moved a few things around when switching to a monorepo recently, so this
> folder might not build with the instructions below. Hang tight, we're on it,
> will fix things if.
Fetch submodules
```sh
git submodule update --init --recursive
```
Install dependencies
```sh
yarn install
```
Run the app
Run in development mode (with hot reload)
```sh
yarn start
yarn dev
```
To recompile automatically using electron-reload, run this in a separate
terminal:
> [!CAUTION]
>
> `yarn dev` is currently not working (we'll fix soon). If you just want to
> build from source and use the generated binary, use `yarn build`.
```bash
yarn watch
Or create a binary for your platform
```sh
yarn build
```
That's the gist of it. For more development related documentation, see
[docs](docs/README.md).

View File

@@ -1,20 +1,30 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ente Photos</title>
</head>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ente Photos</title>
</head>
<body style="background-color: black;">
<div style=" height: 95vh;width: 96vw; display: grid; place-items: center; color: white;">
<div>
<div style="margin-bottom: 10px;">Site unreachable, please try again later</div>
<button onClick="window[`ElectronAPIs`].reloadWindow()">Reload</button>
<body style="background-color: black">
<div
style="
height: 95vh;
width: 96vw;
display: grid;
place-items: center;
color: white;
"
>
<div>
<div style="margin-bottom: 10px">
Site unreachable, please try again later
</div>
<button onClick="window[`ElectronAPIs`].reloadWindow()">
Reload
</button>
</div>
</div>
</div>
</body>
</body>
</html>

View File

@@ -1,30 +1,50 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ente Photos</title>
</head>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ente Photos</title>
</head>
<body style="background-color: black;">
<div style="display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 90vh;">
<div style="width:64px;"><svg version="1.1" id="L9" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100"
enable-background="new 0 0 0 0" xml:space="preserve">
<path fill="#2dc262"
d="M73,50c0-12.7-10.3-23-23-23S27,37.3,27,50 M30.9,50c0-10.5,8.5-19.1,19.1-19.1S69.1,39.5,69.1,50">
<animateTransform attributeName="transform" attributeType="XML" type="rotate" dur="1s"
from="0 50 50" to="360 50 50" repeatCount="indefinite" />
</path>
</svg>
<body style="background-color: black">
<div
style="
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 90vh;
"
>
<div style="width: 64px">
<svg
version="1.1"
id="L9"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
viewBox="0 0 100 100"
enable-background="new 0 0 0 0"
xml:space="preserve"
>
<path
fill="#2dc262"
d="M73,50c0-12.7-10.3-23-23-23S27,37.3,27,50 M30.9,50c0-10.5,8.5-19.1,19.1-19.1S69.1,39.5,69.1,50"
>
<animateTransform
attributeName="transform"
attributeType="XML"
type="rotate"
dur="1s"
from="0 50 50"
to="360 50 50"
repeatCount="indefinite"
/>
</path>
</svg>
</div>
</div>
</div>
</body>
</body>
</html>

View File

@@ -1,24 +1,24 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<title>Electron Updater Example</title>
</head>
<body>
Current version: <span id="version">vX.Y.Z</span>
<div id="messages"></div>
<script>
// Display the current version
let version = window.location.hash.substring(1);
document.getElementById('version').innerText = version;
<head>
<title>Electron Updater Example</title>
</head>
<body>
Current version: <span id="version">vX.Y.Z</span>
<div id="messages"></div>
<script>
// Display the current version
let version = window.location.hash.substring(1);
document.getElementById("version").innerText = version;
// Listen for messages
const {ipcRenderer} = require('electron');
ipcRenderer.on('message', function(event, text) {
var container = document.getElementById('messages');
var message = document.createElement('div');
message.innerHTML = text;
container.appendChild(message);
})
</script>
</body>
</html>
// Listen for messages
const { ipcRenderer } = require("electron");
ipcRenderer.on("message", function (event, text) {
var container = document.getElementById("messages");
var message = document.createElement("div");
message.innerHTML = text;
container.appendChild(message);
});
</script>
</body>
</html>

View File

@@ -1,25 +0,0 @@
Notes on how to upload electron symbols directly to sentry instance (bypassing the CF limits) cc @abhi just for future reference
To upload electron symbols
1. Create a tunnel
```
ssh -p 7426 -N -L 8080:localhost:9000 sentry
```
2. Add the following env file
```
NEXT_PUBLIC_IS_SENTRY_ENABLED = yes
SENTRY_ORG = ente
SENTRY_PROJECT = bhari-frame
SENTRY_URL2 = https://sentry.ente.io/
SENTRY_URL = http://localhost:8080/
SENTRY_AUTH_TOKEN = xxx
SENTRY_LOG_LEVEL = debug
```
3. Run
```
node sentry-symbols.js
```

11
desktop/docs/README.md Normal file
View File

@@ -0,0 +1,11 @@
# Developer docs
If you just want to run the Ente Photos desktop app locally or develop it, you
can do:
yarn install
yarn dev
The docs in this directory provide more details that some developers might find
useful. You might also find the developer docs for
[web](../../web/docs/README.md) useful.

View File

@@ -0,0 +1,14 @@
# Dependencies
See [web/docs/dependencies.md](../../web/docs/dependencies.md) for general web
specific dependencies. See [electron.md](electron.md) for our main dependency,
Electron. The rest of this document describes the remaining, desktop specific
dependencies that are used by the Photos desktop app.
## Electron related
### next-electron-server
This spins up a server for serving files using a protocol handler inside our
Electron process. This allows us to directly use the output produced by `next
build` for loading into our renderer process.

4
desktop/docs/dev.md Normal file
View File

@@ -0,0 +1,4 @@
# Development tips
- `yarn build:quick` is a variant of `yarn build` that uses the
`--config.compression=store` flag to (slightly) speed up electron-builder.

21
desktop/docs/electron.md Normal file
View File

@@ -0,0 +1,21 @@
# Electron
[Electron](https://www.electronjs.org) is a cross-platform (Linux, Windows,
macOS) way for creating desktop apps using TypeScript.
Electron embeds Chromium and Node.js in the generated app's binary. The
generated app thus consists of two separate processes - the _main_ process, and
a _renderer_ process.
- The _main_ process is runs the embedded node. This process can deal with the
host OS - it is conceptually like a `node` repl running on your machine. In our
case, the TypeScript code (in the `src/` directory) gets transpiled by `tsc`
into JavaScript in the `build/app/` directory, which gets bundled in the
generated app's binary and is loaded by the node (main) process when the app
starts.
- The _renderer_ process is a regular web app that gets loaded into the embedded
Chromium. When the main process starts, it creates a new "window" that shows
this embedded Chromium. In our case, we build and bundle a static export of
the [Photos web app](../web/README.md) in the generated app. This gets loaded
by the embedded Chromium at runtime, acting as the app's UI.

View File

@@ -1,10 +1,65 @@
{
"name": "ente",
"productName": "ente",
"version": "1.6.63",
"private": true,
"description": "Desktop client for ente.io",
"description": "Desktop client for Ente Photos",
"author": "Ente <code@ente.io>",
"main": "app/main.js",
"scripts": {
"build": "yarn build-renderer && yarn build-main",
"build-main": "tsc && electron-builder",
"build-main:quick": "tsc && electron-builder --config.compression=store",
"build-renderer": "cd ../web && yarn install && yarn build:photos && cd ../desktop && rm -f out && ln -sf ../web/apps/photos/out",
"build:quick": "yarn build-renderer && yarn build-main:quick",
"dev": "concurrently --names 'main,rndr,tscw' \"yarn dev-main\" \"yarn dev-renderer\" \"yarn dev-main-watch\"",
"dev-main": "tsc && electron app/main.js",
"dev-main-watch": "tsc --watch --preserveWatchOutput",
"dev-renderer": "cd ../web && yarn install && yarn dev:photos",
"postinstall": "electron-builder install-app-deps",
"lint": "yarn prettier --check . && eslint \"src/**/*.ts\"",
"lint-fix": "yarn prettier --write . && eslint --fix src"
},
"dependencies": {
"any-shell-escape": "^0.1.1",
"auto-launch": "^5.0.5",
"chokidar": "^3.5.3",
"compare-versions": "^6.1.0",
"electron-log": "^4.3.5",
"electron-reload": "^2.0.0-alpha.1",
"electron-store": "^8.0.1",
"electron-updater": "^4.3.8",
"ffmpeg-static": "^5.1.0",
"get-folder-size": "^2.0.1",
"html-entities": "^2.4.0",
"jpeg-js": "^0.4.4",
"next-electron-server": "^1",
"node-fetch": "^2.6.7",
"node-stream-zip": "^1.15.0",
"onnxruntime-node": "^1.16.3",
"promise-fs": "^2.1.1"
},
"devDependencies": {
"@types/auto-launch": "^5.0.2",
"@types/ffmpeg-static": "^3.0.1",
"@types/get-folder-size": "^2.0.0",
"@types/node": "18.15.0",
"@types/node-fetch": "^2.6.2",
"@types/promise-fs": "^2.1.1",
"@typescript-eslint/eslint-plugin": "^5.28.0",
"@typescript-eslint/parser": "^5.28.0",
"concurrently": "^7.0.0",
"electron": "^25.8.4",
"electron-builder": "^24.6.4",
"electron-builder-notarize": "^1.2.0",
"electron-download": "^4.1.1",
"eslint": "^7.23.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^8.5.0",
"prettier": "^3",
"prettier-plugin-organize-imports": "^3.2",
"prettier-plugin-packagejson": "^2.4",
"typescript": "^4.2.3"
},
"build": {
"appId": "io.ente.bhari-frame",
"artifactName": "${productName}-${version}-${arch}.${ext}",
@@ -42,7 +97,7 @@
]
}
],
"icon": "./build/icon.icns",
"icon": "./resources/icon.icns",
"category": "Photography"
},
"mac": {
@@ -57,98 +112,24 @@
"x64ArchFiles": "Contents/Resources/ggmlclip-mac"
},
"afterSign": "electron-builder-notarize",
"extraFiles": [
{
"from": "build",
"to": "resources",
"filter": [
"**/*"
]
}
],
"asarUnpack": [
"node_modules/ffmpeg-static/bin/${os}/${arch}/ffmpeg",
"node_modules/ffmpeg-static/index.js",
"node_modules/ffmpeg-static/package.json"
],
"extraFiles": [
{
"from": "build",
"to": "resources"
}
],
"files": [
"app/**/*",
{
"from": "ui/apps/photos",
"to": "ui",
"filter": [
"!**/*",
"out/**/*"
]
}
"out"
]
},
"scripts": {
"postinstall": "electron-builder install-app-deps",
"prebuild": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
"prepare": "husky install",
"lint": "eslint -c .eslintrc --ext .ts src",
"watch": "tsc -w",
"build-main": "yarn install && tsc",
"start-main": "yarn build-main && electron app/main.js",
"start-renderer": "cd ui && yarn install && yarn dev:photos",
"start": "concurrently \"yarn start-main\" \"yarn start-renderer\"",
"build-renderer": "cd ui && yarn install && yarn export:photos",
"build": "yarn build-renderer && yarn build-main",
"test-release": "cross-env IS_TEST_RELEASE=true yarn build && electron-builder --config.compression=store"
},
"author": "ente <code@ente.io>",
"devDependencies": {
"@sentry/cli": "^1.68.0",
"@types/auto-launch": "^5.0.2",
"@types/ffmpeg-static": "^3.0.1",
"@types/get-folder-size": "^2.0.0",
"@types/node": "18.15.0",
"@types/node-fetch": "^2.6.2",
"@types/promise-fs": "^2.1.1",
"@typescript-eslint/eslint-plugin": "^5.28.0",
"@typescript-eslint/parser": "^5.28.0",
"concurrently": "^7.0.0",
"cross-env": "^7.0.3",
"electron": "^25.8.4",
"electron-builder": "^24.6.4",
"electron-builder-notarize": "^1.2.0",
"electron-download": "^4.1.1",
"eslint": "^7.23.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^8.5.0",
"husky": "^8.0.1",
"lint-staged": "^13.0.1",
"prettier": "2.5.1",
"typescript": "^4.2.3"
},
"dependencies": {
"@sentry/electron": "^2.5.1",
"any-shell-escape": "^0.1.1",
"auto-launch": "^5.0.5",
"chokidar": "^3.5.3",
"compare-versions": "^6.1.0",
"electron-log": "^4.3.5",
"electron-reload": "^2.0.0-alpha.1",
"electron-store": "^8.0.1",
"electron-updater": "^4.3.8",
"ffmpeg-static": "^5.1.0",
"get-folder-size": "^2.0.1",
"html-entities": "^2.4.0",
"jpeg-js": "^0.4.4",
"next-electron-server": "file:./thirdparty/next-electron-server",
"node-fetch": "^2.6.7",
"node-stream-zip": "^1.15.0",
"onnxruntime-node": "^1.16.3",
"promise-fs": "^2.1.1"
},
"productName": "ente",
"standard": {
"parser": "babel-eslint"
},
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write --ignore-unknown"
]
}
}

View File

@@ -1,94 +0,0 @@
#!/usr/bin/env node
let SentryCli;
let download;
try {
SentryCli = require('@sentry/cli');
download = require('electron-download');
} catch (e) {
console.error('ERROR: Missing required packages, please run:');
console.error('npm install --save-dev @sentry/cli electron-download');
process.exit(1);
}
const SYMBOL_CACHE_FOLDER = '.electron-symbols';
const sentryCli = new SentryCli('./sentry.properties');
async function main() {
const version = getElectronVersion();
if (!version) {
console.error('Cannot detect electron version, check that electron is installed');
return;
}
console.log('We are starting to download all possible electron symbols');
console.log('We need it in order to symbolicate native crashes');
console.log(
'This step is only needed once whenever you update your electron version',
);
console.log('Just call this script again it should do everything for you.');
let zipPath = await downloadSymbols({
version,
platform: 'darwin',
arch: 'x64',
dsym: true,
});
await sentryCli.execute(['upload-dif', '-t', 'dsym', zipPath], true);
zipPath = await downloadSymbols({
version,
platform: 'win32',
arch: 'ia32',
symbols: true,
});
await sentryCli.execute(['upload-dif', '-t', 'breakpad', zipPath], true);
zipPath = await downloadSymbols({
version,
platform: 'win32',
arch: 'x64',
symbols: true,
});
await sentryCli.execute(['upload-dif', '-t', 'breakpad', zipPath], true);
zipPath = await downloadSymbols({
version,
platform: 'linux',
arch: 'x64',
symbols: true,
});
await sentryCli.execute(['upload-dif', '-t', 'breakpad', zipPath], true);
console.log('Finished downloading and uploading to Sentry');
console.log(`Feel free to delete the ${SYMBOL_CACHE_FOLDER}`);
}
function getElectronVersion() {
try {
return require('electron/package.json').version;
} catch (error) {
return undefined;
}
}
async function downloadSymbols(options) {
return new Promise((resolve, reject) => {
download(
{
...options,
cache: SYMBOL_CACHE_FOLDER,
},
(err, zipPath) => {
if (err) {
reject(err);
} else {
resolve(zipPath);
}
},
);
});
}
main().catch(e => console.error(e));

View File

@@ -1,3 +0,0 @@
defaults.url=https://sentry.ente.io/
defaults.org=ente
defaults.project=desktop-photos

View File

@@ -1,16 +1,16 @@
import { ipcRenderer } from 'electron/renderer';
import path from 'path';
import { existsSync, mkdir, rmSync } from 'promise-fs';
import { DiskCache } from '../services/diskCache';
import { ipcRenderer } from "electron/renderer";
import path from "path";
import { existsSync, mkdir, rmSync } from "promise-fs";
import { DiskCache } from "../services/diskCache";
const ENTE_CACHE_DIR_NAME = 'ente';
const ENTE_CACHE_DIR_NAME = "ente";
export const getCacheDirectory = async () => {
const customCacheDir = await getCustomCacheDirectory();
if (customCacheDir && existsSync(customCacheDir)) {
return customCacheDir;
}
const defaultSystemCacheDir = await ipcRenderer.invoke('get-path', 'cache');
const defaultSystemCacheDir = await ipcRenderer.invoke("get-path", "cache");
return path.join(defaultSystemCacheDir, ENTE_CACHE_DIR_NAME);
};
@@ -22,7 +22,7 @@ const getCacheBucketDir = async (cacheName: string) => {
export async function openDiskCache(
cacheName: string,
cacheLimitInBytes?: number
cacheLimitInBytes?: number,
) {
const cacheBucketDir = await getCacheBucketDir(cacheName);
if (!existsSync(cacheBucketDir)) {
@@ -42,11 +42,11 @@ export async function deleteDiskCache(cacheName: string) {
}
export async function setCustomCacheDirectory(
directory: string
directory: string,
): Promise<void> {
await ipcRenderer.invoke('set-custom-cache-directory', directory);
await ipcRenderer.invoke("set-custom-cache-directory", directory);
}
async function getCustomCacheDirectory(): Promise<string> {
return await ipcRenderer.invoke('get-custom-cache-directory');
return await ipcRenderer.invoke("get-custom-cache-directory");
}

View File

@@ -1,22 +1,21 @@
import { ipcRenderer } from 'electron';
import { writeStream } from '../services/fs';
import { isExecError } from '../utils/error';
import { parseExecError } from '../utils/error';
import { Model } from '../types';
import { ipcRenderer } from "electron";
import { writeStream } from "../services/fs";
import { Model } from "../types";
import { isExecError, parseExecError } from "../utils/error";
export async function computeImageEmbedding(
model: Model,
imageData: Uint8Array
imageData: Uint8Array,
): Promise<Float32Array> {
let tempInputFilePath = null;
try {
tempInputFilePath = await ipcRenderer.invoke('get-temp-file-path', '');
tempInputFilePath = await ipcRenderer.invoke("get-temp-file-path", "");
const imageStream = new Response(imageData.buffer).body;
await writeStream(tempInputFilePath, imageStream);
const embedding = await ipcRenderer.invoke(
'compute-image-embedding',
"compute-image-embedding",
model,
tempInputFilePath
tempInputFilePath,
);
return embedding;
} catch (err) {
@@ -28,20 +27,20 @@ export async function computeImageEmbedding(
}
} finally {
if (tempInputFilePath) {
await ipcRenderer.invoke('remove-temp-file', tempInputFilePath);
await ipcRenderer.invoke("remove-temp-file", tempInputFilePath);
}
}
}
export async function computeTextEmbedding(
model: Model,
text: string
text: string,
): Promise<Float32Array> {
try {
const embedding = await ipcRenderer.invoke(
'compute-text-embedding',
"compute-text-embedding",
model,
text
text,
);
return embedding;
} catch (err) {

View File

@@ -1,44 +1,39 @@
import { ipcRenderer } from 'electron/renderer';
import { logError } from '../services/logging';
import { ipcRenderer } from "electron/renderer";
import { logError } from "../services/logging";
export const selectDirectory = async (): Promise<string> => {
try {
return await ipcRenderer.invoke('select-dir');
return await ipcRenderer.invoke("select-dir");
} catch (e) {
logError(e, 'error while selecting root directory');
logError(e, "error while selecting root directory");
}
};
export const getAppVersion = async (): Promise<string> => {
try {
return await ipcRenderer.invoke('get-app-version');
return await ipcRenderer.invoke("get-app-version");
} catch (e) {
logError(e, 'failed to get release version');
logError(e, "failed to get release version");
throw e;
}
};
export const openDirectory = async (dirPath: string): Promise<void> => {
try {
await ipcRenderer.invoke('open-dir', dirPath);
await ipcRenderer.invoke("open-dir", dirPath);
} catch (e) {
logError(e, 'error while opening directory');
logError(e, "error while opening directory");
throw e;
}
};
export const getPlatform = async (): Promise<'mac' | 'windows' | 'linux'> => {
export const getPlatform = async (): Promise<"mac" | "windows" | "linux"> => {
try {
return await ipcRenderer.invoke('get-platform');
return await ipcRenderer.invoke("get-platform");
} catch (e) {
logError(e, 'failed to get platform');
logError(e, "failed to get platform");
throw e;
}
};
export {
logToDisk,
openLogDirectory,
getSentryUserID,
updateOptOutOfCrashReports,
} from '../services/logging';
export { logToDisk, openLogDirectory } from "../services/logging";

View File

@@ -1,9 +1,8 @@
import { keysStore } from '../stores/keys.store';
import { safeStorageStore } from '../stores/safeStorage.store';
import { uploadStatusStore } from '../stores/upload.store';
import { logError } from '../services/logging';
import { userPreferencesStore } from '../stores/userPreferences.store';
import { watchStore } from '../stores/watch.store';
import { logError } from "../services/logging";
import { keysStore } from "../stores/keys.store";
import { safeStorageStore } from "../stores/safeStorage.store";
import { uploadStatusStore } from "../stores/upload.store";
import { watchStore } from "../stores/watch.store";
export const clearElectronStore = () => {
try {
@@ -11,9 +10,8 @@ export const clearElectronStore = () => {
keysStore.clear();
safeStorageStore.clear();
watchStore.clear();
userPreferencesStore.delete('optOutOfCrashReports');
} catch (e) {
logError(e, 'error while clearing electron store');
logError(e, "error while clearing electron store");
throw e;
}
};

View File

@@ -1,5 +1,5 @@
import { writeStream } from './../services/fs';
import * as fs from 'promise-fs';
import * as fs from "promise-fs";
import { writeStream } from "./../services/fs";
export const exists = (path: string) => {
return fs.existsSync(path);
@@ -13,7 +13,7 @@ export const checkExistsAndCreateDir = async (dirPath: string) => {
export const saveStreamToDisk = async (
filePath: string,
fileStream: ReadableStream<Uint8Array>
fileStream: ReadableStream<Uint8Array>,
) => {
await writeStream(filePath, fileStream);
};

View File

@@ -1,22 +1,22 @@
import { ipcRenderer } from 'electron';
import { existsSync } from 'fs';
import { writeStream } from '../services/fs';
import { logError } from '../services/logging';
import { ElectronFile } from '../types';
import { ipcRenderer } from "electron";
import { existsSync } from "fs";
import { writeStream } from "../services/fs";
import { logError } from "../services/logging";
import { ElectronFile } from "../types";
export async function runFFmpegCmd(
cmd: string[],
inputFile: File | ElectronFile,
outputFileName: string,
dontTimeout?: boolean
dontTimeout?: boolean,
) {
let inputFilePath = null;
let createdTempInputFile = null;
try {
if (!existsSync(inputFile.path)) {
const tempFilePath = await ipcRenderer.invoke(
'get-temp-file-path',
inputFile.name
"get-temp-file-path",
inputFile.name,
);
await writeStream(tempFilePath, await inputFile.stream());
inputFilePath = tempFilePath;
@@ -25,19 +25,19 @@ export async function runFFmpegCmd(
inputFilePath = inputFile.path;
}
const outputFileData = await ipcRenderer.invoke(
'run-ffmpeg-cmd',
"run-ffmpeg-cmd",
cmd,
inputFilePath,
outputFileName,
dontTimeout
dontTimeout,
);
return new File([outputFileData], outputFileName);
} finally {
if (createdTempInputFile) {
try {
await ipcRenderer.invoke('remove-temp-file', inputFilePath);
await ipcRenderer.invoke("remove-temp-file", inputFilePath);
} catch (e) {
logError(e, 'failed to deleteTempFile');
logError(e, "failed to deleteTempFile");
}
}
}

View File

@@ -1,4 +1,4 @@
import { getElectronFile, getDirFilePaths } from '../services/fs';
import { getDirFilePaths, getElectronFile } from "../services/fs";
export async function getDirFiles(dirPath: string) {
const files = await getDirFilePaths(dirPath);
@@ -6,10 +6,10 @@ export async function getDirFiles(dirPath: string) {
return electronFiles;
}
export {
deleteFile,
deleteFolder,
isFolder,
moveFile,
deleteFolder,
deleteFile,
rename,
readTextFile,
} from '../services/fs';
rename,
} from "../services/fs";

Some files were not shown because too many files have changed in this diff Show More