Compare commits

..
347 Commits
Author SHA1 Message Date
Eric Dubé fc51424f86 Merge pull request #332 from HeyPuter/release-please--branches--main--components--puter.com
chore(main): release 1.0.0
2024-05-24 16:25:34 -04:00
github-actions[bot] 5146dc4981 chore(main): release 2.3.0 2024-05-24 16:22:55 -04:00
Nariman Jelveh 103f9d209d Update README.md 2024-05-23 14:32:24 -07:00
KernelDeimos 4508bfac73 Fix cookie issue 2024-05-23 13:30:02 -04:00
Eric Dubé b15dc316d3 Merge pull request #406 from AtkinsSJ/fs-upload-data-type-error
Explicitly reject invalid types for puter.fs.upload() and .write() payloads
2024-05-22 12:13:24 -04:00
KernelDeimos 1f6a2093fb Disallow negative size values 2024-05-21 18:46:34 -04:00
KernelDeimos 90463a0732 Add support for webhook endpoints 2024-05-21 17:25:28 -04:00
Karan Parmar cc45a08388 updated the github links displayed in the Terminal welcome message 2024-05-19 11:52:26 +01:00
KernelDeimos 8cca067991 Fix 8688ha84v 2024-05-17 22:55:40 -04:00
Eric Dubé 80b763c47c Merge pull request #407 from AtkinsSJ/clean-suggested-apps
fix: Remove null or duplicate app entries from suggest_app_for_fsentry()
2024-05-17 15:46:06 -04:00
Eric Dubé 8786024559 Merge pull request #404 from secondtruth/patch-1
Update de.js
2024-05-17 15:42:02 -04:00
Eric Dubé bbb43f53d0 Merge pull request #403 from Zac0511/patch-3
Update fr.js
2024-05-17 15:39:06 -04:00
KernelDeimos 639e40d355 Phoenix shell deployment update 2024-05-17 13:26:44 -04:00
KernelDeimos f964f06f3f Fix 8688h4bwg 2024-05-17 13:05:13 -04:00
KernelDeimos e4543c5f35 Fix 8688ggu00 (2) 2024-05-17 12:32:16 -04:00
Sam Atkins 6900233c5a fix: Remove null or duplicate app entries from suggest_app_for_fsentry() 2024-05-17 15:34:36 +01:00
Sam Atkins 03fe3b6a0d Reject invalid types for puter.fs.upload() items or .write() data
Previously, this would crash in upload() when trying to iterate the
`entries` array, which is undefined when the `items` parameter is an
unsupported type.
2024-05-17 14:39:31 +01:00
Sam Atkins a9c89cef19 refactor: Reduce boilerplate for returning errors from puter.fs.upload() 2024-05-17 14:39:31 +01:00
Zac0511 340b9202c0 Update fr.js 2024-05-17 14:36:54 +02:00
Zac0511 99ca8755f3 Update fr.js 2024-05-17 14:22:22 +02:00
Zac0511 eaf1e96fa2 Update fr.js 2024-05-17 14:19:19 +02:00
Zac0511 f9b5353058 Update fr.js 2024-05-17 14:15:49 +02:00
Zac0511 e0af914c90 Update fr.js 2024-05-17 14:00:43 +02:00
Zac0511 8f19f4dc5b Update fr.js
Complete rework of the file, completly remade from en.js
2024-05-17 13:58:33 +02:00
Zac0511 5f47e7f0fa Update fr.js
Bug repairing... again
2024-05-17 09:55:25 +02:00
Zac0511 9c39b0453d Update fr.js
Little update for some bugs
2024-05-17 09:16:12 +02:00
Zac0511 545fc103b8 Update fr.js
Complete rework of the file for the latest updates
2024-05-17 09:10:55 +02:00
KernelDeimos c55b1e4680 Remove verification requirement on contact us form 2024-05-16 19:08:51 -04:00
Eric Dubé 297db58e68 Merge pull request #405 from HeyPuter/eric/path-builder
Add path builder
2024-05-16 19:08:56 -04:00
KernelDeimos e3f57ee20e Add path builder 2024-05-16 19:02:58 -04:00
KernelDeimos 5031cea040 Update _default.js for deployment purposes 2024-05-16 18:55:59 -04:00
Eric Dubé 6fe126ad5a Merge pull request #386 from HeyPuter/eric/socket-auth
fix(security): Move token for socket.io to request body
2024-05-16 18:02:12 -04:00
KernelDeimos 49b257ecff fix(security): Move token for socket.io to request body
Currently this commit breaks websocket events and needs to
be updated.
2024-05-16 17:58:44 -04:00
KernelDeimos f042b095f1 Fix 8688gxkuj 2024-05-16 17:25:41 -04:00
Christian Neff 43d0936533 Update de.js
Translated:
- 2FA strings
- Task Manager strings
- 2 other scattered strings
2024-05-16 19:51:42 +02:00
KernelDeimos b68873c5f4 Fix 8688grpf1 2024-05-16 12:48:57 -04:00
Zac0511 e1ae9241af Update fr.js 2024-05-16 18:27:12 +02:00
Zac0511 b6ea37c517 Update fr.js
Since there was a lot of text and menus added, and they were not translated, so i just translated them.
2024-05-16 18:06:21 +02:00
KernelDeimos bee0e19eaf Fix 8688ggu00 2024-05-15 20:59:20 -04:00
Eric Dubé f54657a569 Merge pull request #402 from HeyPuter/eric/email-lock
Add locking to save_account
2024-05-15 18:49:03 -04:00
Eric Dubé 1aa27084d0 Merge pull request #396 from AtkinsSJ/xterm-fix
fix(Terminal): Accept input from Chrome on Android
2024-05-15 18:24:02 -04:00
KernelDeimos 691c8f1436 Add locking to save_account 2024-05-15 18:22:54 -04:00
Eric Dubé b72e5b7e02 Merge pull request #401 from HeyPuter/eric/service-patches
Allow patching services
2024-05-15 15:47:14 -04:00
KernelDeimos c70e378973 Add error id for expired auth tokens 2024-05-15 15:42:00 -04:00
KernelDeimos 21444daefb Add jsdoc comments to registerService and patchService 2024-05-15 15:41:37 -04:00
KernelDeimos 2e0d7361cb Add method to patch services 2024-05-15 15:32:18 -04:00
Eric Dubé 6e0b6d84d2 Merge pull request #400 from AtkinsSJ/fix-apierror-includes
fix: Correct APIError imports
2024-05-15 13:51:04 -04:00
Eric Dubé ec59abe3ae Merge pull request #399 from AtkinsSJ/fix-db-scripts
fix: Add missing file extension to 0009_app-prefix-fix.sql in DB init
2024-05-15 13:45:30 -04:00
Sam Atkins 062e23b5c9 fix: Correct APIError imports
APIError is the only thing exported from its file, so we must not wrap
it in {}.
2024-05-15 17:47:15 +01:00
Sam Atkins a8160a8cdc fix: Add missing file extension to 0009_app-prefix-fix.sql in DB init 2024-05-15 10:18:28 +01:00
KernelDeimos 0b093dd57e Revoke other sessions when password is changed 2024-05-14 19:40:57 -04:00
KernelDeimos 923d5878c3 Prevent enable of 2FA without configure 2024-05-14 17:33:14 -04:00
Eric Dubé 9c5849fbce Merge pull request #397 from HeyPuter/eric/anti-csrf
Update for /logout
2024-05-14 14:08:35 -04:00
Sam Atkins 4ef3e53de3 fix(Terminal): Accept input from Chrome on Android
Xterm.js produces two kinds of events: onKey and onData. On a desktop,
these are effectively the same, but on mobile, IME inputs produce data
but not key presses. By listening to onData instead of onKey, we get
that input.

With some experimentation, I also found that we don't need the code to
handle enter, home, end, or Ctrl-Shift-V. All of these function as
expected without that code, so we can remove it and simplify this
further. :^)
2024-05-14 16:10:30 +01:00
Sam Atkins 2656b47640 chore: Update xterm
From version 5.4.0 onwards, xterm scopes its package names as
`@xterm/foo` instead of just `xterm-foo`.

We currently have a copy of xterm.css which we use instead of directly
including the one from the `@xterm/xterm` package, so I've updated the
contents of that too.
2024-05-14 16:10:30 +01:00
Sam Atkins fafbc292ca Remove xterm dependency from Phoenix
This is used by Terminal, not Phoenix.
2024-05-14 16:10:30 +01:00
KernelDeimos 800aef1942 Implement anti-CSRF for logout 2024-05-13 20:40:27 -04:00
KernelDeimos da7f73baa6 Add AntiCSRFService 2024-05-13 19:08:51 -04:00
KernelDeimos afb9d866b5 fix: Fix phoenix app prefix and TokenService test 2024-05-13 18:17:39 -04:00
Eric Dubé 7dc5929cfd Merge pull request #385 from HeyPuter/eric/dry-middleware
Add password requirement to: disable 2FA, change email
2024-05-13 16:38:59 -04:00
KernelDeimos c2f1694107 Require password entry to disable 2FA 2024-05-13 16:00:07 -04:00
KernelDeimos 23215bd6f7 Move change_email/start to password-protected endpoint 2024-05-13 16:00:07 -04:00
KernelDeimos 1493cacb69 Add rate-limiting to new password change endpoint 2024-05-13 16:00:07 -04:00
KernelDeimos 9076fddc0d Add new password change endpoint 2024-05-13 16:00:07 -04:00
KernelDeimos a89c9d59cf Add UserProtectedEndpointsService 2024-05-13 16:00:07 -04:00
KernelDeimos 15dec21118 doc(backend): Document the boot sequence
Now that the boot sequence is better formalized it may be documented.
2024-05-13 16:00:07 -04:00
KernelDeimos d800b12569 refactor(backend): Trigger webserver events in webserver
We were triggering webserver events in Kernel. This change improves
adherence to separation-of-concerns and ensures event cascading is
working as expected. This also better formalizes the boot sequence.
2024-05-13 01:05:49 -04:00
Eric Dubé 89ac491120 Merge pull request #391 from AtkinsSJ/truncate-filename
refactor: Put truncate_filename() helper in its own file
2024-05-10 12:54:46 -04:00
Eric Dubé 981a0f08fe Merge pull request #390 from AtkinsSJ/task-manager-components
refactor: Convert Task Manager to Components
2024-05-10 12:54:30 -04:00
Sam Atkins e53bfe6b62 refactor: Put truncate_filename() helper in its own file
Every user previously set the max_length as window.TRUNCATE_LENGTH, so
I've moved that constant into the truncate_filename file and set it as
the default if max_length is not specified.
2024-05-10 17:46:09 +01:00
Sam Atkins 9bb4570126 Re-use existing Task Manager rows if possible instead of recreating them
Most of the time, we'll already have a TaskManagerRow for the given
process, so we can just update its properties.

Iterating the results from #iter_tasks means we also insert the rows in
the correct order, regardless of their previous order.
2024-05-10 17:41:13 +01:00
Sam Atkins 5b43358219 fix: Only run Component initialization functions once
If the Component gets removed from the DOM and then re-added, it already
has contents, and we don't need to create them again. It also has
already had on_ready called, so that doesn't need to happen again
either.

This fix stops Components duplicating their content elements and
listener callbacks whenever they're moved around the document.
2024-05-10 17:41:01 +01:00
Sam Atkins cf605c8a38 refactor: Convert Task Manager to use Components
This currently behaves the same as it did before: It still recreates the
table contents every half a second. It should also look identical,
though it's possible I missed some small differences.

The component structure is:

TaskManagerTable
- Table
  - TaskManagerRow
  - TaskManagerRow
  - TaskManagerRow
  - ...

TaskManagerRow is implemented so that we can later move to modifying
them in place as the process tree changes, instead of having to replace
them all.

Otherwise, most of the code is just moved around, and not changed much.
2024-05-10 17:41:01 +01:00
Sam Atkins e304f6fc3a Add ability to look up a process by its uuid 2024-05-10 17:38:00 +01:00
Sam Atkins 09cee986f2 Add a Table component, based on the TaskManager table
For now, this is quite basic. The main feature is the sticky header.
2024-05-10 17:38:00 +01:00
Eric Dubé 3992fe1a45 Merge pull request #384 from AtkinsSJ/progress-dialogs
refactor: Replace several existing progress dialogs with one configurable one
2024-05-10 12:25:32 -04:00
Eric Dubé 17e08cafce Merge pull request #380 from AtkinsSJ/eslint-ci
Run ESLint on CI
2024-05-10 12:24:31 -04:00
Sam Atkins 7243ed718f Merge pull request #388 from AtkinsSJ/no-docker-images-for-prs
ci: Stop producing Docker images for PRs
2024-05-10 09:39:31 +01:00
Sam Atkins 387cfd758f Merge pull request #387 from ghostxbh/patch-1
fix: Eliminates duplicate translation keys
2024-05-10 09:31:52 +01:00
Sam Atkins c75a0bd311 ci: Wrap Docker images name with quotes
Not sure if this is required, but my IDE was complaining about it.
2024-05-10 09:29:49 +01:00
Sam Atkins 18633dcd88 ci: Stop producing Docker images for PRs 2024-05-10 09:28:55 +01:00
ghostxbh 5800350b25 fix: Eliminates duplicate translation keys 2024-05-10 10:41:21 +08:00
KernelDeimos cd2daa1910 Require email verification for contact form 2024-05-09 19:40:34 -04:00
KernelDeimos 8b6bbe003d fix(security) Disable 2FA configure if 2FA is enabled 2024-05-09 18:04:58 -04:00
Sam Atkins edebbee9e7 feat: Display upload errors in UIWindowProgress dialog
The object returned from UIWindowProgress() now has a `show_error()`
method, taking a title and message. Calling it will replace the content
of the window with those messages.

I've made use of this for file uploads. The only other place we
currently have errors we could show is for zipping and downloading
files, but we do not always have a progress dialog in that case, so I'll
leave that for now.

I think ideally, we would always create a progress dialog, and it would
then support being invisible initially, but appearing after a delay.
Then we'd always have an object to call `show_error()` on, and it could
then immediately show the dialog. But I'll get to that another day. :^)
2024-05-09 19:00:55 +01:00
Sam Atkins f3269693de Stop dumping binary data to the console
This was freaking out and freezing the Puter server, and my entire
terminal app. XD
2024-05-09 18:28:39 +01:00
Sam Atkins c2c87bf0ba refactor: Replace UIWindowDownloadDirProg with UIWindowProgress 2024-05-09 18:28:39 +01:00
Sam Atkins e525747002 refactor: Replace UIWindowCopyProgress with UIWindowProgress 2024-05-09 18:28:39 +01:00
Sam Atkins 6d8c709de8 Delete unused UIWindowDownloadProgress.js 2024-05-09 18:28:39 +01:00
Sam Atkins f07c13a50c feat: Show "Deleting /foo" in progress window when deleting files
Previously we showed "Moving /foo" which was confusing.

Also, make use of i18n replacements instead of gluing strings together,
because other languages might put the words in a different order. For
now, I've modified all the translations so that the "Moving foo" text
will appear as it did before, but these will require someone who
actually knows the different languages to check and correct them.
2024-05-09 18:19:05 +01:00
Sam Atkins c12312cbd3 refactor: Replace UIWindowMoveProgress with UIWindowProgress 2024-05-09 18:18:27 +01:00
Sam Atkins cb6c098f95 refactor: Replace UIWindowProgressEmptyTrash with UIWindowProgress
I noticed during this that emptying the trash from inside the Trash
window uses a different code path without a progress dialog, so I've
added a TODO to merge that in. I tried just using it directly but the
behaviour is a bit different. (The Trash one makes all the items fade
out.)
2024-05-09 18:17:15 +01:00
Sam Atkins 09ca82e1d8 refactor: Replace UIWindowNewFolderProgress with UIWindowProgress
This previously had code for the cancel button, but that cancel button
didn't exist. I've left the previous on-cancel code commented out with
a TODO.
2024-05-09 15:51:45 +01:00
Sam Atkins 5b565a69d7 refactor: Replace UIWindowUploadProgress with UIWindowProgress 2024-05-09 15:51:45 +01:00
Sam Atkins 52ddfc8801 Introduce a general-purpose progress window
We have 7 of these, which all have very similar code. Let's deduplicate
them! :^)
2024-05-09 15:51:45 +01:00
Sam Atkins df3f7e9a6e Allow Button component to not have button-block class
This needs a better solution for configuring the button's CSS classes,
but this works for now.
2024-05-09 12:38:29 +01:00
Sam Atkins 05aaa5b667 chore: Remove dead code from 2FA development
No `.qr-code-checkbox input`s now exist. Also, `.code-confirm-btn` is
only used by CodeEntryView, which doesn't use this Button component.
2024-05-09 12:12:33 +01:00
KernelDeimos df24c663df Invalidate email confirmation on password change 2024-05-08 22:28:41 -04:00
KernelDeimos 45e7f162a2 Add password change notification 2024-05-08 16:01:20 -04:00
Sam Atkins fbda8c8286 Run ESLint on CI
Run the ESLint static analysis tool on any code that is submitted, to
find possible bugs such as undefined functions and variables. We may
want to adjust the ESLint settings over time, but this seems like a
good start.

This is merged into the previous check-translations.yml action, because
that's also a form of linting. Possibly that could be reimplemented as
an ESLint plugin.
2024-05-08 18:53:37 +01:00
Sam Atkins 8c70efa058 Suppress remaining eslint errors
These two seem like bugs but are unclear to me how to fix, so I've added
FIXMEs.

/puter/packages/backend/src/routers/kvstore/clearItems.js
  41:32  error  'DB_MODE_WRITE' is not defined  no-undef

/puter/packages/backend/src/routers/whoami.js
  104:35  error  'db' is not defined  no-undef
2024-05-08 18:53:36 +01:00
Eric Dubé 65b489883d Merge pull request #381 from AtkinsSJ/web-components
Convert UIWindowThemeDialog to components
2024-05-08 12:15:23 -04:00
Sam Atkins 1b2608d6ee refactor: Replace component definition boilerplate with a function
Also, we can ask the CustomElementRegistry if it has an entry with a
given name, instead of polluting the window object.
2024-05-08 14:46:58 +01:00
Sam Atkins 9267b50666 Convert UIWindowThemeDialog to components
This also fixes the "Reset Colors" button not adjusting the sliders.
2024-05-08 14:46:58 +01:00
Sam Atkins 2604dae83c Resolve eslint issues in new 2FA code
/puter/src/UI/Settings/UITabSecurity.js
  13:13  error  'user' is not defined        no-undef
  31:13  error  'user' is not defined        no-undef
  32:70  error  'user' is not defined        no-undef
  36:30  error  'user' is not defined        no-undef
  40:82  error  'user' is not defined        no-undef
  41:83  error  'user' is not defined        no-undef
  87:41  error  'api_origin' is not defined  no-undef

/puter/src/UI/UIWindow2FASetup.js
  39:33  error  'api_origin' is not defined  no-undef
  51:37  error  'api_origin' is not defined  no-undef
  69:37  error  'api_origin' is not defined  no-undef

/puter/src/UI/UIWindowLogin.js
  202:73  error  'api_origin' is not defined  no-undef
  271:73  error  'api_origin' is not defined  no-undef
2024-05-08 09:49:58 +01:00
Sam Atkins 6778aa4343 Resolve eslint issues in Russian translation
/puter/src/i18n/translations/ru.js
  180:34  error  Irregular whitespace not allowed    no-irregular-whitespace
  257:9   error  Duplicate key 'storage_puter_used'  no-dupe-keys
2024-05-08 09:44:31 +01:00
KernelDeimos 5890b7e7bf Disable password reset token when email or password is changed 2024-05-07 20:18:11 -04:00
KernelDeimos d58aa33d2b Remove taskbar items from localstorage 2024-05-07 20:01:05 -04:00
KernelDeimos f62617a8bf Remove auth_token from /down call 2024-05-07 14:29:09 -04:00
KernelDeimos d20249f29a Send email notifications when 2FA state changes 2024-05-06 21:13:00 -04:00
Eric Dubé 0e16a3f3b4 Merge pull request #370 from HeyPuter/eric/2fa
2FA
2024-05-06 19:33:50 -04:00
Nariman Jelveh 5409547bba Make the 2fa disable prompt a child of the Settings window 2024-05-06 16:16:57 -07:00
KernelDeimos db8e2c3bf2 Address next batch of UX issues 2024-05-06 19:09:28 -04:00
KernelDeimos 4c53ec6dd3 Address UX issues 2024-05-06 18:53:43 -04:00
KernelDeimos b2d678ca95 Cleanup dead code 2024-05-06 16:45:03 -04:00
KernelDeimos adbefb4622 Cleanup log messages 2024-05-06 16:44:23 -04:00
KernelDeimos 429b7033a4 Improve error handling for 2FA rate limit 2024-05-06 16:35:35 -04:00
KernelDeimos 7f3e2852c6 Add rate limits 2024-05-06 16:12:54 -04:00
KernelDeimos 57d9c246c0 Fix css in firefox 2024-05-06 15:47:09 -04:00
KernelDeimos 7fce223a6d Fix OTP test endpoint 2024-05-06 15:40:34 -04:00
KernelDeimos abbbf0d030 Add confirmation for disabling 2FA 2024-05-06 15:36:38 -04:00
KernelDeimos a628358c9f Fix OTP time window 2024-05-06 15:02:14 -04:00
KernelDeimos 918eb3bb67 Put otpauth back on 9.2.4 2024-05-06 02:10:22 -04:00
KernelDeimos ecae1997aa Maybe this?? 2024-05-06 01:58:55 -04:00
KernelDeimos e4c7caa8ea Worth a try 2024-05-06 01:54:02 -04:00
KernelDeimos 54d1f05851 Install otpauth in root package.json because that... matters? 2024-05-06 01:48:25 -04:00
KernelDeimos 1592bc44fc Fix spinner getting stuck 2024-05-06 01:30:32 -04:00
KernelDeimos 77fedee58a Remove artifact 2024-05-06 00:13:24 -04:00
KernelDeimos 63e72a22e0 Fix settings card update 2024-05-06 00:02:46 -04:00
KernelDeimos 00c8ece07e Finish recovery codes 2024-05-06 00:02:46 -04:00
KernelDeimos 60a561c84c Re-use CodeEntryView for login 2024-05-06 00:02:46 -04:00
KernelDeimos 5cbe256120 Add missing part of previous commit 2024-05-06 00:02:46 -04:00
KernelDeimos 4ad50b14d6 Fix the duplicate loading issue 2024-05-06 00:02:46 -04:00
KernelDeimos df88373519 Remove test window open 2024-05-06 00:02:46 -04:00
KernelDeimos 099699198c Tweak QR code sizes 2024-05-06 00:02:46 -04:00
Nariman Jelveh 75bd1bc4c8 Update UIWindow2FASetup.js 2024-05-06 00:02:46 -04:00
Nariman Jelveh 12c883b6fd Remove the confirmation prompt when closing the 2FA setup winow
When exiting a window there should be a confirmation if exiting that window will irreversibly destroy work. For example, when you're working on a document and if you exit unsaved changes will be lost.
This doesn't seem to be the case. What work will be irreversibly lost?
2024-05-06 00:02:46 -04:00
Nariman Jelveh 144d647540 Improve styling 2024-05-06 00:02:46 -04:00
Nariman Jelveh c8a6d109ce Add icon for Security tab and warning/success styling for 2fa card 2024-05-06 00:02:46 -04:00
KernelDeimos 5fa3c6511f Fix padding and enable code 2024-05-06 00:02:46 -04:00
KernelDeimos a2a8f9de74 Fix cache state 2024-05-06 00:02:46 -04:00
KernelDeimos d72d83d0f3 Add i18n entries for 2FA setup 2024-05-06 00:02:46 -04:00
KernelDeimos c91c0afa71 Complete the 2FA setup flow 2024-05-06 00:02:46 -04:00
KernelDeimos a95fcc96be Add text components and styling 2024-05-06 00:02:46 -04:00
KernelDeimos f9c5a688b1 Fix code entry focus on init 2024-05-06 00:02:46 -04:00
KernelDeimos e9b8c452b9 Temporarily disable real check for testing 2024-05-06 00:02:46 -04:00
KernelDeimos 3e380ba844 Add otp test endpoint and next wizard step 2024-05-06 00:02:46 -04:00
KernelDeimos 22234ad1c1 Add the wizardy behaviour 2024-05-06 00:02:46 -04:00
KernelDeimos 662fd13548 Add code entry to 2FA wizard 2024-05-06 00:02:46 -04:00
KernelDeimos a672b8a58c Add UIWindow2FASetup 2024-05-06 00:02:46 -04:00
KernelDeimos 6e0cdb8a6b Document 2FA wizard structure 2024-05-06 00:02:46 -04:00
KernelDeimos 0baa678c8b Add Flexer 2024-05-06 00:02:46 -04:00
KernelDeimos c99747d7f2 Make using web components easier 2024-05-06 00:02:46 -04:00
KernelDeimos 2681a78501 Use username as otp label 2024-05-06 00:02:46 -04:00
KernelDeimos 3bf7737790 Add recovery codes 2024-05-06 00:02:46 -04:00
KernelDeimos 455d3946d6 Add checkboxes and cancel action for 2FA setup 2024-05-06 00:02:46 -04:00
KernelDeimos 2dfecb5287 Add 2fa setting and complete login flow 2024-05-06 00:02:46 -04:00
KernelDeimos abc12bd407 Add otp input at login 2024-05-06 00:02:46 -04:00
KernelDeimos bbf352caa4 Add missing package-lock.json changes 2024-05-06 00:02:46 -04:00
KernelDeimos d7c5c37cf8 Implement backend for 2FA 2024-05-06 00:02:46 -04:00
KernelDeimos 038373cbbc Fix filename inconsistency that breaks Linux support 2024-05-06 00:02:33 -04:00
Nariman Jelveh 321520741d Merge pull request #372 from nyedidikeke/naming-convention-patch-1
refactor: nomenclature, typo fixes, IDE and documentation enhancement 🔨
2024-05-05 19:46:16 -07:00
Didi Keke 2c75c636af docs: environment variable configuration 🌱 2024-05-06 01:21:59 +00:00
Didi Keke 01b7e523d0 chore: comment and fine tune .gitignore settings 🔨 2024-05-06 01:18:40 +00:00
Didi Keke 05d4a28adc chore: format content 📝 2024-05-06 01:14:36 +00:00
Didi Keke b89142c45c chore: include .vscode/extensions.json ⚓
- For recommendation of extensions or otherwise.
2024-05-05 20:31:08 +00:00
Didi Keke f9359bfb73 chore: ignore nested folders 🐜 2024-05-05 20:23:05 +00:00
Didi Keke 4d30740198 fix: typographical errors 🐛 2024-05-05 08:34:50 +00:00
Didi Keke 2d6dfd9002 chore: add word spelling dictionary 👼 2024-05-05 08:15:30 +00:00
Didi Keke 3914a14a2a chore: update .gitignore settings for VS Code 🚀
- All files within the `.vscode/` directory are ignored except for `settings.json`, `tasks.json`, and `launch.json`.
2024-05-05 08:11:13 +00:00
Didi Keke 2949f71691 fix: typographical error 🐛 2024-05-05 07:54:11 +00:00
Didi Keke 551121524c refactor: name from SelfhostedModule to SelfHostedModule 🔨 2024-05-05 07:53:55 +00:00
Nariman Jelveh 038c5e9a6e Merge pull request #371 from mafendi/main
Added Russian translation
2024-05-04 17:22:12 -07:00
Efendi 467aabe5ee Update translations.js
Added ru
2024-05-05 00:09:52 +03:00
Efendi 4f73641f46 Add files via upload 2024-05-05 00:07:07 +03:00
Nariman Jelveh 48e97b5ec2 Update UITaskbarItem.js 2024-05-04 12:34:28 -07:00
KernelDeimos a86106c0c1 Fix save_account token 2024-05-04 14:19:09 -04:00
Nariman Jelveh c9f3693785 Merge branch 'main' of https://github.com/HeyPuter/puter into main 2024-05-03 21:32:26 -07:00
Nariman Jelveh 5151863a94 disable context menu on settings sidebar 2024-05-03 21:32:23 -07:00
Nariman Jelveh 16a81cdc7f Merge pull request #369 from nyedidikeke/patch-1
fix: reliability issue 🐛
2024-05-03 21:10:21 -07:00
Nariman Jelveh ebb6cf2a91 clean up console messages and errors 2024-05-03 20:49:12 -07:00
Didi Keke 1d546d9ef7 fix: reliability issue 🐛 2024-05-04 03:23:28 +00:00
Nariman Jelveh 6bef35b406 Fix issue with passive event listeners via jQuery 2024-05-03 20:21:26 -07:00
Nariman Jelveh ecd9d5493f Fix issue with trash not opening from taskbar 2024-05-03 19:57:48 -07:00
Nariman Jelveh 33a6f4c49f quick fix 2024-05-03 16:56:27 -07:00
Nariman Jelveh 3c92cd3198 Update initgui.js 2024-05-03 12:04:38 -07:00
Eric Dubé 4d0e6b4772 Merge pull request #336 from AtkinsSJ/app-tab-completion
Phoenix: Add tab-completion for command names
2024-05-03 12:39:07 -04:00
Eric Dubé ebdf0d9148 Merge pull request #348 from AtkinsSJ/eslint
Set up eslint, and try to resolve the issues it finds
2024-05-03 12:28:21 -04:00
Sam Atkins 44aa4f1b0a chore: Remove debugger calls
/puter/packages/phoenix/src/ansi-shell/arg-parsers/simple-parser.js
  30:38  warning  Unexpected 'debugger' statement  no-debugger

/puter/packages/phoenix/src/ansi-shell/pipeline/Coupler.js
  71:32  warning  Unexpected 'debugger' statement  no-debugger
2024-05-02 17:41:14 +01:00
Sam Atkins fa7c6bee96 fix: Correct variables used in errors in sign.js
I couldn't figure out how to get a name for the no_suitable_app error
unfortunately, so that's just commented out.

/puter/packages/backend/src/routers/sign.js
   65:74  error  'subject' is not defined  no-undef
  114:59  error  'subject' is not defined  no-undef
2024-05-02 17:39:01 +01:00
Sam Atkins fa3b86fa7e chore: Amend empty blocks in upload.js
/puter/packages/puter-js/src/modules/FileSystem/operations/upload.js
   63:22  error  Empty block statement  no-empty
  173:22  error  Empty block statement  no-empty
2024-05-02 17:31:17 +01:00
Sam Atkins 52d5299374 fix: Use correct variable for version number
/puter/packages/backend/src/services/ComplainAboutVersionsService.js
  30:36  error  'current_version' is not defined  no-undef
2024-05-02 17:30:53 +01:00
Sam Atkins 23d959bf64 chore: Clarify usage of window fields in index.js
/puter/src/index.js
  58:15  error  'loadScript' is not defined  no-undef
  59:15  error  'loadScript' is not defined  no-undef
  65:13  error  'gui_env' is not defined     no-undef
  66:15  error  'loadScript' is not defined  no-undef
  68:15  error  'loadCSS' is not defined     no-undef
  69:15  error  'loadScript' is not defined  no-undef
  73:5   error  'initgui' is not defined     no-undef
2024-05-02 17:26:41 +01:00
Sam Atkins 5198081c2b chore: Fix eslint issues in initgui.js
Almost entirely clarifying use of window fields

/puter/src/initgui.js
    82:28   error  'api_origin' is not defined                                   no-undef
   118:34   error  'url_query_params' is not defined                             no-undef
   120:17   error  'app_query_params' is not defined                             no-undef
   136:8    error  'url_query_params' is not defined                             no-undef
   136:51   error  'url_query_params' is not defined                             no-undef
   136:105  error  'url_query_params' is not defined                             no-undef
   138:14   error  'url_query_params' is not defined                             no-undef
   138:57   error  'url_query_params' is not defined                             no-undef
   138:110  error  'url_query_params' is not defined                             no-undef
   154:8    error  'url_query_params' is not defined                             no-undef
   154:54   error  'url_query_params' is not defined                             no-undef
   154:110  error  'url_query_params' is not defined                             no-undef
   164:17   error  'openerOrigin' is not defined                                 no-undef
   171:30   error  'openerOrigin' is not defined                                 no-undef
   173:37   error  'is_auth' is not defined                                      no-undef
   184:23   error  'getUserAppToken' is not defined                              no-undef
   184:39   error  'openerOrigin' is not defined                                 no-undef
   186:41   error  'is_auth' is not defined                                      no-undef
   195:23   error  'getUserAppToken' is not defined                              no-undef
   195:39   error  'openerOrigin' is not defined                                 no-undef
   205:8    error  'url_query_params' is not defined                             no-undef
   206:32   error  'url_query_params' is not defined                             no-undef
   218:23   error  'url_query_params' is not defined                             no-undef
   219:22   error  'openerOrigin' is not defined                                 no-undef
   219:38   error  'url_query_params' is not defined                             no-undef
   220:26   error  'url_query_params' is not defined                             no-undef
   228:29   error  'embedded_in_popup' is not defined                            no-undef
   238:20   error  'url_query_params' is not defined                             no-undef
   239:21   error  'url_query_params' is not defined                             no-undef
   270:36   error  'openerOrigin' is not defined                                 no-undef
   271:30   error  'checkUserSiteRelationship' is not defined                    no-undef
   271:56   error  'openerOrigin' is not defined                                 no-undef
   274:44   error  'logged_in_users' is not defined                              no-undef
   274:76   error  'userAppToken' is not defined                                 no-undef
   274:92   error  'url_query_params' is not defined                             no-undef
   284:17   error  'userAppToken' is not defined                                 no-undef
   288:25   error  'is_auth' is not defined                                      no-undef
   302:13   error  'url_query_params' is not defined                             no-undef
   303:38   error  'url_query_params' is not defined                             no-undef
   309:17   error  'logout' is not defined                                       no-undef
   331:13   error  'update_auth_data' is not defined                             no-undef
   363:8    error  'is_auth' is not defined                                      no-undef
   388:13   error  'update_auth_data' is not defined                             no-undef
   394:23   error  'get_auto_arrange_data' is not defined                        no-undef
   395:31   error  'desktop_path' is not defined                                 no-undef
   403:30   error  'url_query_params' is not defined                             no-undef
   405:38   error  'getUserAppToken' is not defined                              no-undef
   405:62   error  'openerOrigin' is not defined                                 no-undef
   415:35   error  'user' is not defined                                         no-undef
   417:24   error  'openerOrigin' is not defined                                 no-undef
   430:24   error  'openerOrigin' is not defined                                 no-undef
   438:20   error  'openerOrigin' is not defined                                 no-undef
   439:37   error  'getAppUIDFromOrigin' is not defined                          no-undef
   439:57   error  'openerOrigin' is not defined                                 no-undef
   444:35   error  'url_query_params' is not defined                             no-undef
   508:46   error  'url_query_params' is not defined                             no-undef
   630:54   error  'busy_indicator_hide_delay' is not defined                    no-undef
   636:49   error  'busy_indicator_hide_delay' is not defined                    no-undef
   647:13   error  'update_sites_cache' is not defined                           no-undef
   656:9    error  'refresh_desktop_background' is not defined                   no-undef
   661:9    error  'is_auth' is not defined                                      no-undef
   661:23   error  'first_visit_ever' is not defined                             no-undef
   662:12   error  'logged_in_users' is not defined                              no-undef
   679:14   error  'is_auth' is not defined                                      no-undef
   679:27   error  'first_visit_ever' is not defined                             no-undef
   693:12   error  'url_query_params' is not defined                             no-undef
   696:47   error  'url_query_params' is not defined                             no-undef
   704:18   error  'gui_origin' is not defined                                   no-undef
   715:17   error  'update_auth_data' is not defined                             no-undef
   728:8    error  'feature_flags' is not defined                                no-undef
   746:19   error  'get_auto_arrange_data' is not defined                        no-undef
   747:27   error  'desktop_path' is not defined                                 no-undef
   755:26   error  'url_query_params' is not defined                             no-undef
   758:34   error  'getUserAppToken' is not defined                              no-undef
   758:58   error  'openerOrigin' is not defined                                 no-undef
   768:31   error  'user' is not defined                                         no-undef
   770:20   error  'openerOrigin' is not defined                                 no-undef
   783:20   error  'openerOrigin' is not defined                                 no-undef
   792:16   error  'openerOrigin' is not defined                                 no-undef
   793:33   error  'getAppUIDFromOrigin' is not defined                          no-undef
   793:53   error  'openerOrigin' is not defined                                 no-undef
   801:31   error  'url_query_params' is not defined                             no-undef
   864:42   error  'url_query_params' is not defined                             no-undef
   987:50   error  'busy_indicator_hide_delay' is not defined                    no-undef
   993:45   error  'busy_indicator_hide_delay' is not defined                    no-undef
  1021:13   error  'update_explorer_footer_selected_items_count' is not defined  no-undef
  1057:13   error  'active_item_container' is not defined                        no-undef
  1061:17   error  'active_item_container' is not defined                        no-undef
  1065:21   error  'active_item_container' is not defined                        no-undef
  1071:9    error  'active_element' is not defined                               no-undef
  1179:21   error  'select_ctxmenu_item' is not defined                          no-undef
  1185:21   error  'select_ctxmenu_item' is not defined                          no-undef
  1198:21   error  'select_ctxmenu_item' is not defined                          no-undef
  1211:21   error  'select_ctxmenu_item' is not defined                          no-undef
  1222:25   error  'select_ctxmenu_item' is not defined                          no-undef
  1255:22   error  'active_item_container' is not defined                        no-undef
  1256:39   error  'active_item_container' is not defined                        no-undef
  1257:21   error  'active_element' is not defined                               no-undef
  1258:23   error  'active_item_container' is not defined                        no-undef
  1263:27   error  'active_item_container' is not defined                        no-undef
  1264:39   error  'active_item_container' is not defined                        no-undef
  1267:27   error  'active_item_container' is not defined                        no-undef
  1268:39   error  'active_element' is not defined                               no-undef
  1268:74   error  'active_element' is not defined                               no-undef
  1268:93   error  'active_element' is not defined                               no-undef
  1271:27   error  'active_item_container' is not defined                        no-undef
  1272:39   error  'active_item_container' is not defined                        no-undef
  1275:39   error  'active_element' is not defined                               no-undef
  1275:74   error  'active_element' is not defined                               no-undef
  1275:93   error  'active_element' is not defined                               no-undef
  1323:114  error  'active_item_container' is not defined                        no-undef
  1331:21   error  'active_element' is not defined                               no-undef
  1334:27   error  'active_item_container' is not defined                        no-undef
  1390:37   error  'active_element' is not defined                               no-undef
  1407:31   error  'delete_item' is not defined                                  no-undef
  1419:37   error  'active_element' is not defined                               no-undef
  1419:115  error  'trash_path' is not defined                                   no-undef
  1436:31   error  'delete_item' is not defined                                  no-undef
  1438:55   error  'trash_path' is not defined                                   no-undef
  1445:59   error  'trash_path' is not defined                                   no-undef
  1446:61   error  'trash_path' is not defined                                   no-undef
  1452:37   error  'active_element' is not defined                               no-undef
  1456:25   error  'move_items' is not defined                                   no-undef
  1456:53   error  'trash_path' is not defined                                   no-undef
  1467:16   error  'keypress_item_seach_term' is not defined                     no-undef
  1468:30   error  'keypress_item_seach_buffer_timeout' is not defined           no-undef
  1470:13   error  'keypress_item_seach_buffer_timeout' is not defined           no-undef
  1471:17   error  'keypress_item_seach_term' is not defined                     no-undef
  1474:13   error  'keypress_item_seach_term' is not defined                     no-undef
  1477:38   error  'active_item_container' is not defined                        no-undef
  1480:108  error  'keypress_item_seach_term' is not defined                     no-undef
  1485:30   error  'active_item_container' is not defined                        no-undef
  1487:78   error  'keypress_item_seach_term' is not defined                     no-undef
  1505:19   error  'active_item_container' is not defined                        no-undef
  1509:17   error  'update_explorer_footer_selected_items_count' is not defined  no-undef
  1509:63   error  'active_element' is not defined                               no-undef
  1518:16   error  'keypress_item_seach_term' is not defined                     no-undef
  1519:30   error  'keypress_item_seach_buffer_timeout' is not defined           no-undef
  1521:13   error  'keypress_item_seach_buffer_timeout' is not defined           no-undef
  1522:17   error  'keypress_item_seach_term' is not defined                     no-undef
  1525:13   error  'keypress_item_seach_term' is not defined                     no-undef
  1531:97   error  'keypress_item_seach_term' is not defined                     no-undef
  1538:67   error  'keypress_item_seach_term' is not defined                     no-undef
  1581:39   error  'active_element' is not defined                               no-undef
  1583:39   error  'active_element' is not defined                               no-undef
  1590:17   error  'update_explorer_footer_selected_items_count' is not defined  no-undef
  1600:36   error  'active_element' is not defined                               no-undef
  1602:36   error  'active_element' is not defined                               no-undef
  1615:15   error  'mouseover_window' is not defined                             no-undef
  1616:15   error  'mouseover_window' is not defined                             no-undef
  1616:55   error  'trash_path' is not defined                                   no-undef
  1621:38   error  'active_element' is not defined                               no-undef
  1623:38   error  'active_element' is not defined                               no-undef
  1628:21   error  'clipboard' is not defined                                    no-undef
  1629:21   error  'clipboard_op' is not defined                                 no-undef
  1632:58   error  'trash_path' is not defined                                   no-undef
  1636:25   error  'clipboard' is not defined                                    no-undef
  1648:38   error  'active_element' is not defined                               no-undef
  1650:38   error  'active_element' is not defined                               no-undef
  1655:21   error  'clipboard' is not defined                                    no-undef
  1656:21   error  'clipboard_op' is not defined                                 no-undef
  1658:25   error  'clipboard' is not defined                                    no-undef
  1668:107  error  'last_enter_pressed_to_rename_ts' is not defined              no-undef
  1682:21   error  'launch_app' is not defined                                   no-undef
  1705:21   error  'select_ctxmenu_item' is not defined                          no-undef
  1713:21   error  'active_item_container' is not defined                        no-undef
  1714:37   error  'active_item_container' is not defined                        no-undef
  1717:25   error  'open_item' is not defined                                    no-undef
  1736:16   error  'clipboard' is not defined                                    no-undef
  1745:37   error  'trash_path' is not defined                                   no-undef
  1745:74   error  'trash_path' is not defined                                   no-undef
  1745:96   error  'clipboard_op' is not defined                                 no-undef
  1748:20   error  'clipboard_op' is not defined                                 no-undef
  1749:21   error  'copy_clipboard_items' is not defined                         no-undef
  1750:25   error  'clipboard_op' is not defined                                 no-undef
  1751:21   error  'move_clipboard_items' is not defined                         no-undef
  1760:13   error  'undo_last_action' is not defined                             no-undef
  1767:9    error  'mouseX' is not defined                                       no-undef
  1768:9    error  'mouseY' is not defined                                       no-undef
  1771:13   error  'mouseX' is not defined                                       no-undef
  1771:29   error  'mouseY' is not defined                                       no-undef
  1771:38   error  'toolbar_height' is not defined                               no-undef
  1771:63   error  'mouseX' is not defined                                       no-undef
  1771:78   error  'mouseY' is not defined                                       no-undef
  1772:13   error  'current_active_snap_zone' is not defined                     no-undef
  1774:17   error  'mouseX' is not defined                                       no-undef
  1774:32   error  'mouseY' is not defined                                       no-undef
  1774:49   error  'mouseY' is not defined                                       no-undef
  1774:58   error  'desktop_height' is not defined                               no-undef
  1775:13   error  'current_active_snap_zone' is not defined                     no-undef
  1777:17   error  'mouseX' is not defined                                       no-undef
  1777:32   error  'mouseY' is not defined                                       no-undef
  1777:41   error  'desktop_height' is not defined                               no-undef
  1778:13   error  'current_active_snap_zone' is not defined                     no-undef
  1780:17   error  'mouseX' is not defined                                       no-undef
  1780:26   error  'desktop_width' is not defined                                no-undef
  1780:48   error  'mouseY' is not defined                                       no-undef
  1780:65   error  'mouseY' is not defined                                       no-undef
  1780:74   error  'desktop_height' is not defined                               no-undef
  1781:13   error  'current_active_snap_zone' is not defined                     no-undef
  1783:18   error  'mouseX' is not defined                                       no-undef
  1783:27   error  'desktop_width' is not defined                                no-undef
  1783:50   error  'mouseY' is not defined                                       no-undef
  1783:59   error  'toolbar_height' is not defined                               no-undef
  1783:84   error  'mouseX' is not defined                                       no-undef
  1783:93   error  'desktop_width' is not defined                                no-undef
  1783:115  error  'mouseY' is not defined                                       no-undef
  1784:13   error  'current_active_snap_zone' is not defined                     no-undef
  1786:17   error  'mouseX' is not defined                                       no-undef
  1786:26   error  'desktop_width' is not defined                                no-undef
  1786:48   error  'mouseY' is not defined                                       no-undef
  1786:58   error  'desktop_height' is not defined                               no-undef
  1787:13   error  'current_active_snap_zone' is not defined                     no-undef
  1789:17   error  'mouseY' is not defined                                       no-undef
  1789:26   error  'toolbar_height' is not defined                               no-undef
  1789:49   error  'mouseX' is not defined                                       no-undef
  1789:66   error  'mouseX' is not defined                                       no-undef
  1789:75   error  'desktop_width' is not defined                                no-undef
  1790:13   error  'current_active_snap_zone' is not defined                     no-undef
  1793:13   error  'current_active_snap_zone' is not defined                     no-undef
  1802:21   error  'mouseX' is not defined                                       no-undef
  1802:41   error  'mouseX' is not defined                                       no-undef
  1802:75   error  'mouseY' is not defined                                       no-undef
  1802:95   error  'mouseY' is not defined                                       no-undef
  1819:21   error  'mouseX' is not defined                                       no-undef
  1819:41   error  'mouseX' is not defined                                       no-undef
  1819:75   error  'mouseY' is not defined                                       no-undef
  1819:95   error  'mouseY' is not defined                                       no-undef
  1840:12   error  'mouseover_window' is not defined                             no-undef
  1841:15   error  'mouseover_window' is not defined                             no-undef
  1876:17   error  'upload_items' is not defined                                 no-undef
  1934:21   error  'logout' is not defined                                       no-undef
  1936:17   error  'logout' is not defined                                       no-undef
  1946:22   error  'gui_origin' is not defined                                   no-undef
  1951:50   error  'auth_token' is not defined                                   no-undef
  1958:18   error  Empty block statement                                         no-empty
2024-05-02 17:23:20 +01:00
Sam Atkins b6c491171c chore: Fix eslint issues in helper/ files
/puter/src/helpers/determine_active_container_parent.js
  22:30  error  'active_element' is not defined         no-undef
  25:30  error  'active_element' is not defined         no-undef
  29:30  error  'active_element' is not defined         no-undef
  32:41  error  'active_element' is not defined         no-undef
  32:61  error  'active_element' is not defined         no-undef
  33:30  error  'active_element' is not defined         no-undef
  36:41  error  'active_item_container' is not defined  no-undef
  37:28  error  'active_item_container' is not defined  no-undef

/puter/src/helpers/download.js
  51:27  error  'api_origin' is not defined           no-undef
  52:59  error  'auth_token' is not defined           no-undef
  92:16  error  'operation_cancelled' is not defined  no-undef

/puter/src/helpers/new_context_menu_item.js
  38:21  error  'create_folder' is not defined  no-undef
  48:21  error  'create_file' is not defined    no-undef
  56:21  error  'create_file' is not defined    no-undef
  70:25  error  'create_file' is not defined    no-undef

/puter/src/helpers/refresh_item_container.js
   83:13  error  'update_window_layout' is not defined                no-undef
   86:13  error  'update_details_layout_sort_visuals' is not defined  no-undef
  124:35  error  'trash_path' is not defined                          no-undef
  162:29  error  Empty block statement                                no-empty
  166:51  error  'path' is not defined                                no-undef
  168:34  error  'trash_path' is not defined                          no-undef
  168:62  error  'appdata_path' is not defined                        no-undef
  171:38  error  'desktop_item_positions' is not defined              no-undef
  178:37  error  'item_icon' is not defined                           no-undef
  207:31  error  'trash_path' is not defined                          no-undef
  216:21  error  'sort_items' is not defined                          no-undef
  217:26  error  Empty block statement                                no-empty
  222:13  error  'sort_items' is not defined                          no-undef
  233:17  error  'update_explorer_footer_item_count' is not defined   no-undef

/puter/src/helpers/update_title_based_on_uploads.js
  21:41  error  'active_uploads' is not defined  no-undef
  22:59  error  'active_uploads' is not defined  no-undef
  23:51  error  'active_uploads' is not defined  no-undef
  27:51  error  'active_uploads' is not defined  no-undef
2024-05-02 17:02:53 +01:00
Sam Atkins eefc0d41e1 chore: Fix eslint issues in helpers.js
Most of these are window fields that wanted `window.` prepended, but a
couple of issues are code that was using undefined variables (`ht` and
`dir_uuid`) and some switch-cases that I believe are intentionally
falling through.

/puter/src/helpers.js
    39:55   error  'auth_token' is not defined                                                                                            no-undef
    47:14   error  'api_origin' is not defined                                                                                            no-undef
    55:40   error  'auth_token' is not defined                                                                                            no-undef
    59:17   error  'logout' is not defined                                                                                                no-undef
   199:14   error  'api_origin' is not defined                                                                                            no-undef
   208:40   error  'auth_token' is not defined                                                                                            no-undef
   212:17   error  'logout' is not defined                                                                                                no-undef
   224:14   error  'api_origin' is not defined                                                                                            no-undef
   234:40   error  'auth_token' is not defined                                                                                            no-undef
   238:17   error  'logout' is not defined                                                                                                no-undef
   316:13   error  Expected a 'break' statement before 'case'                                                                             no-fallthrough
   323:13   error  Expected a 'break' statement before 'case'                                                                             no-fallthrough
   330:13   error  Expected a 'break' statement before 'case'                                                                             no-fallthrough
   337:13   error  Expected a 'break' statement before 'case'                                                                             no-fallthrough
   367:47   error  Unnecessary escape character: \/                                                                                       no-useless-escape
   411:14   error  'isString' is not defined                                                                                              no-undef
   420:47   error  'config' is not defined                                                                                                no-undef
   519:21   error  'globToRegExp' is not defined                                                                                          no-undef
   651:14   error  Empty block statement                                                                                                  no-empty
   656:9    error  'update_auth_data' is not defined                                                                                      no-undef
   678:36   error  'api_origin' is not defined                                                                                            no-undef
   722:5    error  'update_user_preferences' is not defined                                                                               no-undef
   740:24   error  'uuidv4' is not defined                                                                                                no-undef
   746:9    error  'appCallbackFunctions' is not defined                                                                                  no-undef
   789:14   error  'api_origin' is not defined                                                                                            no-undef
   794:40   error  'auth_token' is not defined                                                                                            no-undef
   861:33   error  'trash_path' is not defined                                                                                            no-undef
   867:21   error  Empty block statement                                                                                                  no-empty
   889:70   error  'trash_path' is not defined                                                                                            no-undef
   891:59   error  'trash_path' is not defined                                                                                            no-undef
   894:49   error  'trash_path' is not defined                                                                                            no-undef
   907:29   error  'docs_path' is not defined                                                                                             no-undef
   909:35   error  'pictures_path' is not defined                                                                                         no-undef
   911:35   error  'home_path' is not defined                                                                                             no-undef
   913:35   error  'videos_path' is not defined                                                                                           no-undef
   915:35   error  'desktop_path' is not defined                                                                                          no-undef
  1037:5    error  'getItem' is not defined                                                                                               no-undef
  1041:17   error  'setItem' is not defined                                                                                               no-undef
  1070:54   error  Empty block statement                                                                                                  no-empty
  1089:51   error  'ht' is not defined                                                                                                    no-undef
  1091:20   error  'desktop_loading_fade_delay' is not defined                                                                            no-undef
  1150:27   error  'operation_id' is not defined                                                                                          no-undef
  1151:5    error  'operation_cancelled' is not defined                                                                                   no-undef
  1169:21   error  'activate_item_name_editor' is not defined                                                                             no-undef
  1172:21   error  'actions_history' is not defined                                                                                       no-undef
  1181:54   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  1187:37   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  1211:21   error  'activate_item_name_editor' is not defined                                                                             no-undef
  1214:21   error  'actions_history' is not defined                                                                                       no-undef
  1245:22   error  'operation_id' is not defined                                                                                          no-undef
  1246:5    error  'operation_cancelled' is not defined                                                                                   no-undef
  1249:5    error  'update_explorer_footer_selected_items_count' is not defined                                                           no-undef
  1263:24   error  'clipboard' is not defined                                                                                             no-undef
  1264:29   error  'clipboard' is not defined                                                                                             no-undef
  1273:20   error  'operation_cancelled' is not defined                                                                                   no-undef
  1302:38   error  'clipboard' is not defined                                                                                             no-undef
  1303:38   error  'clipboard' is not defined                                                                                             no-undef
  1327:9    error  'actions_history' is not defined                                                                                       no-undef
  1335:40   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  1341:29   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  1354:22   error  'operation_id' is not defined                                                                                          no-undef
  1377:20   error  'operation_cancelled' is not defined                                                                                   no-undef
  1432:9    error  'actions_history' is not defined                                                                                       no-undef
  1440:40   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  1446:29   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  1486:17   error  'update_explorer_footer_item_count' is not defined                                                                     no-undef
  1487:17   error  'update_explorer_footer_selected_items_count' is not defined                                                           no-undef
  1500:8    error  'clipboard' is not defined                                                                                             no-undef
  1501:24   error  'clipboard' is not defined                                                                                             no-undef
  1502:61   error  'clipboard' is not defined                                                                                             no-undef
  1505:13   error  'move_items' is not defined                                                                                            no-undef
  1508:5    error  'clipboard' is not defined                                                                                             no-undef
  1537:23   error  'api_origin' is not defined                                                                                            no-undef
  1537:84   error  'auth_token' is not defined                                                                                            no-undef
  1556:34   error  'uuidv4' is not defined                                                                                                no-undef
  1565:45   error  'get_apps' is not defined                                                                                              no-undef
  1572:13   error  This branch can never execute. Its condition is a duplicate or covered by previous conditions in the if-else-if chain  no-dupe-else-if
  1639:21   error  'root_dirname' is not defined                                                                                          no-undef
  1684:37   error  'gui_origin' is not defined                                                                                            no-undef
  1711:60   error  'app_domain' is not defined                                                                                            no-undef
  1723:64   error  'auth_token' is not defined                                                                                            no-undef
  1737:49   error  'auth_token' is not defined                                                                                            no-undef
  1748:12   error  'api_origin' is not defined                                                                                            no-undef
  1749:64   error  'api_origin' is not defined                                                                                            no-undef
  1800:13   error  'launch_apps' is not defined                                                                                           no-undef
  1803:13   error  'launch_apps' is not defined                                                                                           no-undef
  1803:43   error  'launch_apps' is not defined                                                                                           no-undef
  1806:13   error  'launch_apps' is not defined                                                                                           no-undef
  1806:34   error  'launch_apps' is not defined                                                                                           no-undef
  1810:22   error  'api_origin' is not defined                                                                                            no-undef
  1819:48   error  'auth_token' is not defined                                                                                            no-undef
  1867:56   error  'trash_path' is not defined                                                                                            no-undef
  1873:34   error  'trash_path' is not defined                                                                                            no-undef
  1942:30   error  'busy_indicator_hide_delay' is not defined                                                                             no-undef
  1948:25   error  'busy_indicator_hide_delay' is not defined                                                                             no-undef
  1954:48   error  'user_preferences' is not defined                                                                                      no-undef
  1955:9    error  'launch_app' is not defined                                                                                            no-undef
  1956:19   error  'user_preferences' is not defined                                                                                      no-undef
  1967:9    error  'launch_app' is not defined                                                                                            no-undef
  1978:25   error  'item_icon' is not defined                                                                                             no-undef
  1992:9    error  'window_nav_history' is not defined                                                                                    no-undef
  1992:45   error  'window_nav_history' is not defined                                                                                    no-undef
  1992:88   error  'window_nav_history_current_position' is not defined                                                                   no-undef
  1993:9    error  'window_nav_history' is not defined                                                                                    no-undef
  1994:9    error  'window_nav_history_current_position' is not defined                                                                   no-undef
  1996:9    error  'update_window_path' is not defined                                                                                    no-undef
  2009:22   error  'api_origin' is not defined                                                                                            no-undef
  2017:48   error  'auth_token' is not defined                                                                                            no-undef
  2021:25   error  'logout' is not defined                                                                                                no-undef
  2025:20   error  Empty block statement                                                                                                  no-empty
  2029:70   error  'suggest_apps_for_fsentry' is not defined                                                                              no-undef
  2040:17   error  'unzipItem' is not defined                                                                                             no-undef
  2057:17   error  'trigger_download' is not defined                                                                                      no-undef
  2065:13   error  'launch_app' is not defined                                                                                            no-undef
  2087:22   error  'operation_id' is not defined                                                                                          no-undef
  2088:5    error  'operation_cancelled' is not defined                                                                                   no-undef
  2129:12   error  'operation_cancelled' is not defined                                                                                   no-undef
  2166:30   error  Empty block statement                                                                                                  no-empty
  2173:20   error  'operation_cancelled' is not defined                                                                                   no-undef
  2182:34   error  'trash_path' is not defined                                                                                            no-undef
  2196:55   error  'trash_path' is not defined                                                                                            no-undef
  2196:116  error  'trash_path' is not defined                                                                                            no-undef
  2197:57   error  'trash_path' is not defined                                                                                            no-undef
  2201:46   error  'trash_path' is not defined                                                                                            no-undef
  2215:47   error  'trash_path' is not defined                                                                                            no-undef
  2254:25   error  'update_explorer_footer_item_count' is not defined                                                                     no-undef
  2255:25   error  'update_explorer_footer_selected_items_count' is not defined                                                           no-undef
  2260:34   error  'trash_path' is not defined                                                                                            no-undef
  2270:25   error  'update_window_path' is not defined                                                                                    no-undef
  2274:34   error  'trash_path' is not defined                                                                                            no-undef
  2279:46   error  'dir_uuid' is not defined                                                                                              no-undef
  2302:33   error  'item_icon' is not defined                                                                                             no-undef
  2303:42   error  'trash_path' is not defined                                                                                            no-undef
  2309:47   error  'trash_path' is not defined                                                                                            no-undef
  2331:41   error  'item_icon' is not defined                                                                                             no-undef
  2343:21   error  'sort_items' is not defined                                                                                            no-undef
  2348:21   error  'sort_items' is not defined                                                                                            no-undef
  2391:47   error  'trash_path' is not defined                                                                                            no-undef
  2397:51   error  'trash_path' is not defined                                                                                            no-undef
  2398:53   error  'trash_path' is not defined                                                                                            no-undef
  2413:34   error  'trash_path' is not defined                                                                                            no-undef
  2414:9    error  'actions_history' is not defined                                                                                       no-undef
  2418:40   error  'trash_path' is not defined                                                                                            no-undef
  2419:9    error  'actions_history' is not defined                                                                                       no-undef
  2428:12   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  2641:21   error  'upload_items' is not defined                                                                                          no-undef
  2659:21   error  'trash_path' is not defined                                                                                            no-undef
  2679:21   error  'show_save_account_notice_if_needed' is not defined                                                                    no-undef
  2683:17   error  'active_uploads' is not defined                                                                                        no-undef
  2695:17   error  'active_uploads' is not defined                                                                                        no-undef
  2714:17   error  'actions_history' is not defined                                                                                       no-undef
  2722:25   error  'show_save_account_notice_if_needed' is not defined                                                                    no-undef
  2723:33   error  'upload_progress_hide_delay' is not defined                                                                            no-undef
  2726:24   error  'active_uploads' is not defined                                                                                        no-undef
  2733:24   error  'active_uploads' is not defined                                                                                        no-undef
  2739:24   error  'active_uploads' is not defined                                                                                        no-undef
  2766:17   error  'uuidv4' is not defined                                                                                                no-undef
  2772:16   error  'trash_path' is not defined                                                                                            no-undef
  2782:47   error  'trash_path' is not defined                                                                                            no-undef
  2782:108  error  'trash_path' is not defined                                                                                            no-undef
  2783:37   error  'trash_path' is not defined                                                                                            no-undef
  2786:36   error  'trash_path' is not defined                                                                                            no-undef
  2788:13   error  'update_explorer_footer_item_count' is not defined                                                                     no-undef
  2788:71   error  'trash_path' is not defined                                                                                            no-undef
  2793:28   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  2799:28   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  2815:18   error  'api_origin' is not defined                                                                                            no-undef
  2818:42   error  'auth_token' is not defined                                                                                            no-undef
  2991:28   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  2998:28   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  3066:24   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  3074:24   error  'copy_progress_hide_delay' is not defined                                                                              no-undef
  3086:17   error  'actions_history' is not defined                                                                                       no-undef
  3095:17   error  'suggest_apps_for_fsentry' is not defined                                                                              no-undef
  3104:95   error  'truncate_filename' is not defined                                                                                     no-undef
  3104:123  error  'TRUNCATE_LENGTH' is not defined                                                                                       no-undef
  3111:84   error  'item_icon' is not defined                                                                                             no-undef
  3150:23   error  'update_sites_cache' is not defined                                                                                    no-undef
  3153:27   error  'determine_website_url' is not defined                                                                                 no-undef
  3158:17   error  'update_window_path' is not defined                                                                                    no-undef
  3166:17   error  'sort_items' is not defined                                                                                            no-undef
  3171:34   error  'truncate_filename' is not defined                                                                                     no-undef
  3171:66   error  'TRUNCATE_LENGTH' is not defined                                                                                       no-undef
  3205:9    error  'actions_history' is not defined                                                                                       no-undef
  3206:29   error  'actions_history' is not defined                                                                                       no-undef
  3211:13   error  'undo_create_file_or_folder' is not defined                                                                            no-undef
  3214:13   error  'rename_file' is not defined                                                                                           no-undef
  3217:13   error  'undo_upload' is not defined                                                                                           no-undef
  3220:13   error  'undo_copy' is not defined                                                                                             no-undef
  3223:13   error  'undo_move' is not defined                                                                                             no-undef
  3226:13   error  'undo_delete' is not defined                                                                                           no-undef
  3249:26   error  'get_html_element_from_options' is not defined                                                                         no-undef
  3251:9    error  'move_items' is not defined                                                                                            no-undef
  3257:26   error  'get_html_element_from_options' is not defined                                                                         no-undef
  3259:9    error  'move_items' is not defined                                                                                            no-undef
  3265:21   error  'global_element_id' is not defined                                                                                     no-undef
  3282:23   error  'determine_website_url' is not defined                                                                                 no-undef
  3324:42   error  'byte_format' is not defined                                                                                           no-undef
  3381:116  error  'truncate_filename' is not defined                                                                                     no-undef
  3381:148  error  'TRUNCATE_LENGTH' is not defined                                                                                       no-undef
  3396:5    error  'is_auto_arrange_enabled' is not defined                                                                               no-undef
  3398:5    error  'desktop_item_positions' is not defined                                                                                no-undef
  3408:8    error  'reset_item_positions' is not defined                                                                                  no-undef
  3409:9    error  'delete_desktop_item_positions' is not defined                                                                         no-undef
  3415:26   error  'desktop_item_positions' is not defined                                                                                no-undef
  3426:44   error  'desktop_item_positions' is not defined                                                                                no-undef
  3430:5    error  'desktop_item_positions' is not defined                                                                                no-undef
  3438:28   error  'is_fullscreen' is not defined                                                                                         no-undef
  3462:14   error  'window_for_app_instance' is not defined                                                                               no-undef
  3469:31   error  'iframe_for_app_instance' is not defined                                                                               no-undef
  3483:23   error  'window_for_app_instance' is not defined                                                                               no-undef
  3514:42   error  Unnecessary escape character: \[                                                                                       no-useless-escape
  3514:59   error  Unnecessary escape character: \/                                                                                       no-useless-escape
2024-05-02 16:54:17 +01:00
Sam Atkins e5cd2bed87 chore: Clarify usage of window fields in globals.js
/puter/src/globals.js
  124:65  error  'first_visit_animation' is not defined  no-undef
2024-05-02 11:21:51 +01:00
Sam Atkins 766da39138 chore: Clarify usage of window fields in UIWindowSignup.js
/puter/src/UI/UIWindowSignup.js
  154:22  error  'is_email' is not defined                 no-undef
  170:35  error  'check_password_strength' is not defined  no-undef
  188:22  error  'gui_origin' is not defined               no-undef
  203:21  error  'update_auth_data' is not defined         no-undef
2024-05-02 11:21:51 +01:00
Sam Atkins 72c0e118c3 chore: Clarify usage of window fields in UIWindowSessionList.js
/puter/src/UI/UIWindowSessionList.js
   33:117  error  'icons' is not defined             no-undef
   34:41   error  'logged_in_users' is not defined   no-undef
   35:32   error  'logged_in_users' is not defined   no-undef
  134:36   error  'logged_in_users' is not defined   no-undef
  141:17   error  'update_auth_data' is not defined  no-undef
2024-05-02 11:21:51 +01:00
Sam Atkins 66cdf98190 chore: Clarify usage of window fields in UIWindowSaveAccount.js
/puter/src/UI/UIWindowSaveAccount.js
  130:22  error  'api_origin' is not defined        no-undef
  142:48  error  'auth_token' is not defined        no-undef
  145:21  error  'update_auth_data' is not defined  no-undef
2024-05-02 11:21:51 +01:00
Sam Atkins e5d4be6250 chore: Clarify usage of window fields in UIWindowRefer.js
/puter/src/UI/UIWindowRefer.js
  25:20  error  'gui_origin' is not defined  no-undef
  25:37  error  'user' is not defined        no-undef
  73:30  error  'socialLink' is not defined  no-undef
2024-05-02 11:21:51 +01:00
Sam Atkins 130b57b986 chore: Clarify usage of window fields in UIWindowRecoverPassword.js
/puter/src/UI/UIWindowRecoverPassword.js
   84:16  error  'is_email' is not defined    no-undef
   91:22  error  'api_origin' is not defined  no-undef
  101:25  error  'logout' is not defined      no-undef
2024-05-02 11:21:51 +01:00
Sam Atkins 2f30ae7a82 fix: Make url variable accessible to all users of it
Line 107 tries to use `url` but can't see it.

Also, clarify usage of window fields.

/puter/src/UI/UIWindowPublishWebsite.js
   67:67  error  'generate_identifier' is not defined  no-undef
  107:54  error  'url' is not defined                  no-undef
  110:17  error  'update_sites_cache' is not defined   no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins e983e9e9b7 chore: Clarify usage of window fields in UIWindowNewPassword.js
/puter/src/UI/UIWindowNewPassword.js
   48:38  error  'api_origin' is not defined               no-undef
  153:35  error  'check_password_strength' is not defined  no-undef
  163:22  error  'api_origin' is not defined               no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins b042f3c738 chore: Clarify usage of window fields in UIWindowMyWebsites.js
/puter/src/UI/UIWindowMyWebsites.js
  156:30  error  'api_origin' is not defined  no-undef
  164:56  error  'auth_token' is not defined  no-undef
  168:33  error  'logout' is not defined      no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins ece37b62f2 chore: Clarify usage of window fields in progress dialogs
/puter/src/UI/UIWindowMoveProgress.js
  74:9  error  'operation_cancelled' is not defined  no-undef

/puter/src/UI/UIWindowNewFolderProgress.js
  67:9  error  'operation_cancelled' is not defined  no-undef

/puter/src/UI/UIWindowProgressEmptyTrash.js
  67:9  error  'operation_cancelled' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins abc70f2e92 chore: Clarify usage of window fields in UIWindowManageSessions.js
/puter/src/UI/UIWindowManageSessions.js
   91:41  error  'api_origin' is not defined  no-undef
  122:37  error  'api_origin' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 2ed258cb69 chore: Clarify usage of window fields in UIWindowLogin.js
/puter/src/UI/UIWindowLogin.js
  141:16  error  'is_email' is not defined          no-undef
  160:22  error  'gui_origin' is not defined        no-undef
  167:21  error  'update_auth_data' is not defined  no-undef
  180:59  error  'gui_origin' is not defined        no-undef
  186:29  error  'app_domain' is not defined        no-undef
  188:54  error  'gui_origin' is not defined        no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 6903ce0043 chore: Clarify usage of window fields in UIWindowItemProperties.js
/puter/src/UI/UIWindowItemProperties.js
  135:26   error  Empty block statement              no-empty
  147:120  error  'byte_format' is not defined       no-undef
  155:395  error  'extractSubdomain' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 0ebcbe516c chore: Clarify usage of window fields in UIWindowFontPicker.js
/puter/src/UI/UIWindowFontPicker.js
  45:12  error  'isString' is not defined             no-undef
  95:21  error  'scrollParentToChild' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins c44e0ca737 chore: Clarify usage of window fields in UIWindowFeedback.js
/puter/src/UI/UIWindowFeedback.js
  79:22  error  'api_origin' is not defined  no-undef
  84:48  error  'auth_token' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 7f050dc61a chore: Clarify usage of window fields in UIWindowDownloadProgress.js
/puter/src/UI/UIWindowDownloadProgress.js
  74:9  error  'operation_cancelled' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 93e13cdb06 chore: Clarify usage of window fields in UIWindowDesktopBGSettings.js
/puter/src/UI/UIWindowDesktopBGSettings.js
  168:26  error  'api_origin' is not defined  no-undef
  178:52  error  'auth_token' is not defined  no-undef
  182:29  error  'logout' is not defined      no-undef
  188:24  error  Empty block statement        no-empty
2024-05-02 11:21:50 +01:00
Sam Atkins dea3bc1a7f chore: Clarify use of window fields in UIWindowEmailConfirmationRequired
/puter/src/UI/UIWindowEmailConfirmationRequired.js
  113:26  error  'api_origin' is not defined         no-undef
  121:52  error  'auth_token' is not defined         no-undef
  125:29  error  'logout' is not defined             no-undef
  131:29  error  'refresh_user_data' is not defined  no-undef
  160:22  error  'api_origin' is not defined         no-undef
  165:48  error  'auth_token' is not defined         no-undef
  169:25  error  'logout' is not defined             no-undef
  188:13  error  'logout' is not defined             no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 2f6fcdb878 chore: Clarify usage of window fields in UIWindowDownloadProgress.js
/puter/src/UI/UIWindowDownloadProgress.js
  74:9  error  'operation_cancelled' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 3de32c2acc chore: Clarify usage of window fields in UIWindowColorPicker.js
/puter/src/UI/UIWindowColorPicker.js
  26:12  error  'isString' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins ff28d2919b chore: Clarify usage of window fields in UIWindowChangeUsername.js
/puter/src/UI/UIWindowChangeUsername.js
   97:18  error  'api_origin' is not defined  no-undef
  101:44  error  'auth_token' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins e3fb25cf45 chore: Clarify usage of window fields in UIWindowChangePassword.js
/puter/src/UI/UIWindowChangePassword.js
  107:31  error  'check_password_strength' is not defined  no-undef
  117:18  error  'api_origin' is not defined               no-undef
  121:44  error  'auth_token' is not defined               no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins d39fd8659e chore: Clarify usage of window fields in UIWindow.js
And also add some missing imports.

/puter/src/UI/UIWindow.js
    33:20   error  'global_element_id' is not defined                            no-undef
    34:5    error  'last_window_zindex' is not defined                           no-undef
    48:5    error  'window_stack' is not defined                                 no-undef
    69:52   error  'uuidv4' is not defined                                       no-undef
    90:9    error  'is_embedded' is not defined                                  no-undef
   174:52   error  'last_window_zindex' is not defined                           no-undef
   174:94   error  'last_window_zindex' is not defined                           no-undef
   244:77   error  'is_embedded' is not defined                                  no-undef
   289:57   error  'navbar_path' is not defined                                  no-undef
   436:25   error  'launch_app' is not defined                                   no-undef
   456:9    error  'window_nav_history' is not defined                           no-undef
   457:9    error  'window_nav_history_current_position' is not defined          no-undef
   524:9    error  'animate_window_opening' is not defined                       no-undef
   599:17   error  'validate_fsentry_name' is not defined                        no-undef
   790:9    error  'navbar_path_droppable' is not defined                        no-undef
   791:9    error  'sidebar_item_droppable' is not defined                       no-undef
   801:33   error  'window_nav_history' is not defined                           no-undef
   801:63   error  'window_nav_history_current_position' is not defined          no-undef
   804:46   error  'root_dirname' is not defined                                 no-undef
   812:17   error  'window_nav_history_current_position' is not defined          no-undef
   812:68   error  'window_nav_history_current_position' is not defined          no-undef
   813:34   error  'window_nav_history' is not defined                           no-undef
   813:64   error  'window_nav_history_current_position' is not defined          no-undef
   815:17   error  'update_window_path' is not defined                           no-undef
   825:29   error  'window_nav_history_current_position' is not defined          no-undef
   826:38   error  'window_nav_history' is not defined                           no-undef
   834:25   error  'window_nav_history_current_position' is not defined          no-undef
   835:42   error  'window_nav_history' is not defined                           no-undef
   835:72   error  'window_nav_history_current_position' is not defined          no-undef
   840:59   error  'root_dirname' is not defined                                 no-undef
   847:29   error  'update_window_path' is not defined                           no-undef
   869:33   error  'window_nav_history' is not defined                           no-undef
   869:63   error  'window_nav_history_current_position' is not defined          no-undef
   872:46   error  'root_dirname' is not defined                                 no-undef
   880:17   error  'window_nav_history_current_position' is not defined          no-undef
   882:37   error  'window_nav_history' is not defined                           no-undef
   882:67   error  'window_nav_history_current_position' is not defined          no-undef
   885:21   error  'update_window_path' is not defined                           no-undef
   896:29   error  'window_nav_history_current_position' is not defined          no-undef
   896:86   error  'window_nav_history' is not defined                           no-undef
   897:38   error  'window_nav_history' is not defined                           no-undef
   905:25   error  'window_nav_history_current_position' is not defined          no-undef
   906:42   error  'window_nav_history' is not defined                           no-undef
   906:72   error  'window_nav_history_current_position' is not defined          no-undef
   911:59   error  'root_dirname' is not defined                                 no-undef
   918:29   error  'update_window_path' is not defined                           no-undef
   941:50   error  'root_dirname' is not defined                                 no-undef
   950:17   error  'window_nav_history' is not defined                           no-undef
   950:46   error  'window_nav_history' is not defined                           no-undef
   950:82   error  'window_nav_history_current_position' is not defined          no-undef
   951:17   error  'window_nav_history' is not defined                           no-undef
   952:17   error  'window_nav_history_current_position' is not defined          no-undef
   954:17   error  'update_window_path' is not defined                           no-undef
   968:25   error  'update_window_layout' is not defined                         no-undef
   983:25   error  'update_window_layout' is not defined                         no-undef
   986:25   error  'update_window_layout' is not defined                         no-undef
   997:13   error  'is_auth' is not defined                                      no-undef
  1023:13   error  'update_explorer_footer_selected_items_count' is not defined  no-undef
  1106:21   error  'active_element' is not defined                               no-undef
  1117:13   error  'update_explorer_footer_selected_items_count' is not defined  no-undef
  1143:18   error  'mouseover_window' is not defined                             no-undef
  1205:82   error  'mouseX' is not defined                                       no-undef
  1205:107  error  'mouseY' is not defined                                       no-undef
  1219:83   error  'mouseover_window' is not defined                             no-undef
  1244:31   error  'mouseover_window' is not defined                             no-undef
  1246:17   error  'copy_items' is not defined                                   no-undef
  1246:45   error  'mouseover_window' is not defined                             no-undef
  1252:21   error  'create_shortcut' is not defined                              no-undef
  1255:27   error  'mouseover_window' is not defined                             no-undef
  1264:17   error  'move_items' is not defined                                   no-undef
  1264:45   error  'mouseover_window' is not defined                             no-undef
  1286:13   error  'scale_window' is not defined                                 no-undef
  1302:13   error  'scale_window' is not defined                                 no-undef
  1359:21   error  'upload_items' is not defined                                 no-undef
  1413:47   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1414:49   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1420:53   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1435:17   error  'last_window_zindex' is not defined                           no-undef
  1460:29   error  'current_active_snap_zone' is not defined                     no-undef
  1469:50   error  'current_active_snap_zone' is not defined                     no-undef
  1473:43   error  'desktop_height' is not defined                               no-undef
  1474:40   error  'toolbar_height' is not defined                               no-undef
  1476:44   error  'last_window_zindex' is not defined                           no-undef
  1480:55   error  'current_active_snap_zone' is not defined                     no-undef
  1484:43   error  'desktop_height' is not defined                               no-undef
  1485:40   error  'toolbar_height' is not defined                               no-undef
  1487:44   error  'last_window_zindex' is not defined                           no-undef
  1491:55   error  'current_active_snap_zone' is not defined                     no-undef
  1495:43   error  'desktop_height' is not defined                               no-undef
  1496:40   error  'toolbar_height' is not defined                               no-undef
  1497:41   error  'desktop_width' is not defined                                no-undef
  1498:44   error  'last_window_zindex' is not defined                           no-undef
  1502:55   error  'current_active_snap_zone' is not defined                     no-undef
  1506:43   error  'desktop_height' is not defined                               no-undef
  1507:40   error  'toolbar_height' is not defined                               no-undef
  1510:44   error  'last_window_zindex' is not defined                           no-undef
  1514:55   error  'current_active_snap_zone' is not defined                     no-undef
  1517:42   error  'desktop_width' is not defined                                no-undef
  1518:43   error  'desktop_height' is not defined                               no-undef
  1519:40   error  'toolbar_height' is not defined                               no-undef
  1521:44   error  'last_window_zindex' is not defined                           no-undef
  1525:55   error  'current_active_snap_zone' is not defined                     no-undef
  1528:40   error  'toolbar_height' is not defined                               no-undef
  1528:57   error  'desktop_height' is not defined                               no-undef
  1531:43   error  'desktop_height' is not defined                               no-undef
  1532:44   error  'last_window_zindex' is not defined                           no-undef
  1536:55   error  'current_active_snap_zone' is not defined                     no-undef
  1539:40   error  'toolbar_height' is not defined                               no-undef
  1539:57   error  'desktop_height' is not defined                               no-undef
  1540:41   error  'desktop_width' is not defined                                no-undef
  1542:43   error  'desktop_height' is not defined                               no-undef
  1543:44   error  'last_window_zindex' is not defined                           no-undef
  1559:52   error  'current_active_snap_zone' is not defined                     no-undef
  1590:28   error  'current_active_snap_zone' is not defined                     no-undef
  1592:40   error  'toolbar_height' is not defined                               no-undef
  1595:43   error  'desktop_height' is not defined                               no-undef
  1599:33   error  'current_active_snap_zone' is not defined                     no-undef
  1601:40   error  'toolbar_height' is not defined                               no-undef
  1604:43   error  'desktop_height' is not defined                               no-undef
  1608:33   error  'current_active_snap_zone' is not defined                     no-undef
  1610:40   error  'toolbar_height' is not defined                               no-undef
  1613:43   error  'desktop_height' is not defined                               no-undef
  1617:33   error  'current_active_snap_zone' is not defined                     no-undef
  1619:40   error  'toolbar_height' is not defined                               no-undef
  1619:57   error  'desktop_height' is not defined                               no-undef
  1622:43   error  'desktop_height' is not defined                               no-undef
  1626:33   error  'current_active_snap_zone' is not defined                     no-undef
  1628:40   error  'toolbar_height' is not defined                               no-undef
  1628:57   error  'desktop_height' is not defined                               no-undef
  1629:41   error  'desktop_width' is not defined                                no-undef
  1631:43   error  'desktop_height' is not defined                               no-undef
  1635:33   error  'current_active_snap_zone' is not defined                     no-undef
  1637:40   error  'toolbar_height' is not defined                               no-undef
  1640:43   error  'desktop_height' is not defined                               no-undef
  1644:33   error  'current_active_snap_zone' is not defined                     no-undef
  1645:29   error  'scale_window' is not defined                                 no-undef
  1656:51   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1657:53   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1663:57   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1674:71   error  'taskbar_height' is not defined                               no-undef
  1676:51   error  'taskbar_height' is not defined                               no-undef
  1703:35   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1718:36   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1719:49   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1725:42   error  'window_width_threshold_for_sidebar' is not defined           no-undef
  1733:50   error  'toolbar_height' is not defined                               no-undef
  1734:38   error  'toolbar_height' is not defined                               no-undef
  1736:32   error  'toolbar_height' is not defined                               no-undef
  1773:13   error  'setItem' is not defined                                      no-undef
  1820:21   error  'scale_window' is not defined                                 no-undef
  1867:51   error  'trash_path' is not defined                                   no-undef
  1881:41   error  'sort_items' is not defined                                   no-undef
  1882:41   error  'set_sort_by' is not defined                                  no-undef
  1889:41   error  'sort_items' is not defined                                   no-undef
  1890:41   error  'set_sort_by' is not defined                                  no-undef
  1897:41   error  'sort_items' is not defined                                   no-undef
  1898:41   error  'set_sort_by' is not defined                                  no-undef
  1905:41   error  'sort_items' is not defined                                   no-undef
  1906:41   error  'set_sort_by' is not defined                                  no-undef
  1918:41   error  'sort_items' is not defined                                   no-undef
  1919:41   error  'set_sort_by' is not defined                                  no-undef
  1927:41   error  'sort_items' is not defined                                   no-undef
  1928:41   error  'set_sort_by' is not defined                                  no-undef
  1973:40   error  'clipboard' is not defined                                    no-undef
  1975:36   error  'clipboard_op' is not defined                                 no-undef
  1976:37   error  'copy_clipboard_items' is not defined                         no-undef
  1977:41   error  'clipboard_op' is not defined                                 no-undef
  1978:37   error  'move_clipboard_items' is not defined                         no-undef
  1986:39   error  'actions_history' is not defined                              no-undef
  1988:33   error  'undo_last_action' is not defined                             no-undef
  1998:33   error  'init_upload_using_dialog' is not defined                     no-undef
  2014:48   error  'UIWindowSaveAccount' is not defined                          no-undef
  2023:85   error  'UIWindowEmailConfirmationRequired' is not defined            no-undef
  2036:33   error  'launch_app' is not defined                                   no-undef
  2059:44   error  'mouseX' is not defined                                       no-undef
  2063:43   error  'mouseY' is not defined                                       no-undef
  2102:68   error  'trash_path' is not defined                                   no-undef
  2103:37   error  'delete_item' is not defined                                  no-undef
  2110:67   error  'trash_path' is not defined                                   no-undef
  2110:128  error  'trash_path' is not defined                                   no-undef
  2146:21   error  'upload_items' is not defined                                 no-undef
  2163:13   error  'enter_fullpage_mode' is not defined                          no-undef
  2173:8    error  'active_element' is not defined                               no-undef
  2174:9    error  'active_element' is not defined                               no-undef
  2195:25   error  'item_icon' is not defined                                    no-undef
  2210:9    error  'window_nav_history' is not defined                           no-undef
  2210:45   error  'window_nav_history' is not defined                           no-undef
  2210:88   error  'window_nav_history_current_position' is not defined          no-undef
  2211:9    error  'window_nav_history' is not defined                           no-undef
  2212:9    error  'window_nav_history_current_position' is not defined          no-undef
  2214:9    error  'update_window_path' is not defined                           no-undef
  2257:37   error  'item_icon' is not defined                                    no-undef
  2364:9    error  'update_window_path' is not defined                           no-undef
  2380:38   error  'root_dirname' is not defined                                 no-undef
  2389:9    error  'window_nav_history' is not defined                           no-undef
  2389:45   error  'window_nav_history' is not defined                           no-undef
  2389:88   error  'window_nav_history_current_position' is not defined          no-undef
  2390:9    error  'window_nav_history' is not defined                           no-undef
  2391:9    error  'window_nav_history_current_position' is not defined          no-undef
  2391:62   error  'window_nav_history' is not defined                           no-undef
  2392:9    error  'update_window_path' is not defined                           no-undef
  2436:59   error  'root_dirname' is not defined                                 no-undef
  2453:19   error  'clipboard' is not defined                                    no-undef
  2455:16   error  'clipboard_op' is not defined                                 no-undef
  2456:17   error  'copy_clipboard_items' is not defined                         no-undef
  2457:21   error  'clipboard_op' is not defined                                 no-undef
  2458:17   error  'move_clipboard_items' is not defined                         no-undef
  2484:18   error  'mouseover_window' is not defined                             no-undef
  2503:21   error  'create_shortcut' is not defined                              no-undef
  2515:17   error  'move_items' is not defined                                   no-undef
  2525:18   error  'mouseover_window' is not defined                             no-undef
  2605:12   error  'window_nav_history' is not defined                           no-undef
  2605:42   error  'window_nav_history' is not defined                           no-undef
  2605:84   error  'window_nav_history_current_position' is not defined          no-undef
  2612:12   error  'window_nav_history_current_position' is not defined          no-undef
  2626:55   error  'navbar_path' is not defined                                  no-undef
  2687:17   error  'update_window_layout' is not defined                         no-undef
  2690:21   error  'update_details_layout_sort_visuals' is not defined           no-undef
  2698:13   error  'update_window_path' is not defined                           no-undef
  2707:54   error  'root_dirname' is not defined                                 no-undef
  2712:9    error  'navbar_path_droppable' is not defined                        no-undef
  2715:5    error  'update_explorer_footer_selected_items_count' is not defined  no-undef
  2727:18   error  'mouseover_window' is not defined                             no-undef
  2746:21   error  'create_shortcut' is not defined                              no-undef
  2758:17   error  'move_items' is not defined                                   no-undef
  2768:18   error  'mouseover_window' is not defined                             no-undef
  2807:36   error  'sendWindowWillCloseMsg' is not defined                       no-undef
  2819:23   error  'window_stack' is not defined                                 no-undef
  2829:17   error  'remove_taskbar_item' is not defined                          no-undef
  2836:17   error  'exit_fullpage_mode' is not defined                           no-undef
  2853:31   error  'window_stack' is not defined                                 no-undef
  2854:73   error  'window_stack' is not defined                                 no-undef
  2854:86   error  'window_stack' is not defined                                 no-undef
  2857:47   error  'window_stack' is not defined                                 no-undef
  2857:60   error  'window_stack' is not defined                                 no-undef
  2916:22   error  'window_stack' is not defined                                 no-undef
  2924:13   error  'active_item_container' is not defined                        no-undef
  2949:20   error  'toolbar_height' is not defined                               no-undef
  3007:14   error  'api_origin' is not defined                                   no-undef
  3017:40   error  'auth_token' is not defined                                   no-undef
  3021:17   error  'logout' is not defined                                       no-undef
  3083:43   error  'last_window_zindex' is not defined                           no-undef
  3123:38   error  'last_window_zindex' is not defined                           no-undef
  3127:98   error  'last_window_zindex' is not defined                           no-undef
  3131:100  error  'last_window_zindex' is not defined                           no-undef
  3147:81   error  'mouseX' is not defined                                       no-undef
  3147:106  error  'mouseY' is not defined                                       no-undef
  3151:9    error  'active_item_container' is not defined                        no-undef
  3153:34   error  'active_item_container' is not defined                        no-undef
  3155:9    error  'window_stack' is not defined                                 no-undef
  3157:11   error  'active_item_container' is not defined                        no-undef
  3252:5    error  'sort_items' is not defined                                   no-undef
  3253:5    error  'set_sort_by' is not defined                                  no-undef
  3258:14   error  'api_origin' is not defined                                   no-undef
  3267:40   error  'auth_token' is not defined                                   no-undef
  3271:17   error  'logout' is not defined                                       no-undef
  3280:21   error  'update_details_layout_sort_visuals' is not defined           no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 126b00b35c chore: Clarify usage of window fields in UITaskbarItem.js
/puter/src/UI/UITaskbarItem.js
   31:24  error  'global_element_id' is not defined    no-undef
  124:21  error  'launch_app' is not defined           no-undef
  143:21  error  'empty_trash' is not defined          no-undef
  158:25  error  'remove_taskbar_item' is not defined  no-undef
  160:21  error  'update_taskbar' is not defined       no-undef
  174:21  error  'update_taskbar' is not defined       no-undef
  250:73  error  'mouseover_window' is not defined     no-undef
  254:33  error  'path' is not defined                 no-undef
  297:21  error  'launch_app' is not defined           no-undef
  328:89  error  'mouseover_window' is not defined     no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 94291c4968 chore: Clarify usage of window fields in UITaskbar.js
/puter/src/UI/UITaskbar.js
   24:5    error  'global_element_id' is not defined      no-undef
   31:14   error  'api_origin' is not defined             no-undef
   36:40   error  'auth_token' is not defined             no-undef
   44:33   error  'global_element_id' is not defined      no-undef
   77:17   error  'launch_apps' is not defined            no-undef
   77:33   error  'launch_apps' is not defined            no-undef
   77:55   error  'launch_apps' is not defined            no-undef
   79:17   error  'launch_apps' is not defined            no-undef
   80:26   error  'api_origin' is not defined             no-undef
   85:52   error  'auth_token' is not defined             no-undef
   99:16   error  'launch_apps' is not defined            no-undef
  105:88   error  'launch_apps' is not defined            no-undef
  106:38   error  'launch_apps' is not defined            no-undef
  119:16   error  'launch_apps' is not defined            no-undef
  121:107  error  'launch_apps' is not defined            no-undef
  125:45   error  'launch_apps' is not defined            no-undef
  126:38   error  'launch_apps' is not defined            no-undef
  179:17   error  'launch_app' is not defined             no-undef
  201:25   error  'launch_app' is not defined             no-undef
  215:39   error  'trash_path' is not defined             no-undef
  228:68   error  'trash_path' is not defined             no-undef
  230:17   error  'launch_app' is not defined             no-undef
  236:13   error  'move_items' is not defined             no-undef
  236:31   error  'trash_path' is not defined             no-undef
  240:5    error  'make_taskbar_sortable' is not defined  no-undef
  262:22   error  Empty block statement                   no-empty
  284:29   error  'launch_app' is not defined             no-undef
  297:17   error  'update_taskbar' is not defined         no-undef
  301:17   error  'update_taskbar' is not defined         no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins a5821815bf chore: Clarify usage of window fields in UIPrompt.js
/puter/src/UI/UIPrompt.js
  26:12  error  'isString' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins c5612beff9 chore: Clarify usage of window fields in UIPopover.js
/puter/src/UI/UIPopover.js
  28:5   error  'global_element_id' is not defined  no-undef
  33:30  error  'global_element_id' is not defined  no-undef
  40:59  error  'global_element_id' is not defined  no-undef
  76:59  error  'taskbar_height' is not defined     no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins eecaf759ea chore: Clarify usage of window fields in UINotification.js
The click handler also makes use of the `options` parameter from
UINotification(), which isn't available there, so I've commented that
out. This needs more work.

/puter/src/UI/UINotification.js
  21:5   error  'global_element_id' is not defined  no-undef
  26:39  error  'global_element_id' is not defined  no-undef
  34:73  error  'global_element_id' is not defined  no-undef
  47:14  error  'toolbar_height' is not defined     no-undef
  55:12  error  'options' is not defined            no-undef
  55:36  error  'options' is not defined            no-undef
  56:13  error  'options' is not defined            no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 620a1a1334 chore: Clarify usage of window fields in UIItem.js
/puter/src/UI/UIItem.js
    42:21   error  'global_element_id' is not defined                            no-undef
    62:23   error  'determine_website_url' is not defined                        no-undef
   100:58   error  'timeago' is not defined                                      no-undef
   104:42   error  'byte_format' is not defined                                  no-undef
   161:151  error  'truncate_filename' is not defined                            no-undef
   161:183  error  'TRUNCATE_LENGTH' is not defined                              no-undef
   171:5    error  'show_or_hide_empty_folder_message' is not defined            no-undef
   178:64   error  'trash_path' is not defined                                   no-undef
   186:9    error  'update_explorer_footer_item_count' is not defined            no-undef
   190:10   error  'is_auto_arrange_enabled' is not defined                      no-undef
   217:21   error  'upload_items' is not defined                                 no-undef
   336:16   error  'mouseover_window' is not defined                             no-undef
   337:39   error  'mouseover_window' is not defined                             no-undef
   338:23   error  'mouseover_window' is not defined                             no-undef
   341:24   error  'mouseX' is not defined                                       no-undef
   341:46   error  'mouseX' is not defined                                       no-undef
   341:69   error  'mouseY' is not defined                                       no-undef
   341:90   error  'mouseY' is not defined                                       no-undef
   342:88   error  'mouseX' is not defined                                       no-undef
   342:113  error  'mouseY' is not defined                                       no-undef
   350:18   error  'is_auto_arrange_enabled' is not defined                      no-undef
   350:78   error  'trash_path' is not defined                                   no-undef
   352:17   error  'mouseover_window' is not defined                             no-undef
   358:17   error  'desktop_item_positions' is not defined                       no-undef
   359:17   error  'save_desktop_item_positions' is not defined                  no-undef
   383:73   error  'mouseover_window' is not defined                             no-undef
   427:21   error  'launch_app' is not defined                                   no-undef
   448:25   error  'copy_items' is not defined                                   no-undef
   450:25   error  'copy_items' is not defined                                   no-undef
   455:25   error  'create_shortcut' is not defined                              no-undef
   468:32   error  'desktop_item_positions' is not defined                       no-undef
   469:25   error  'save_desktop_item_positions' is not defined                  no-undef
   471:21   error  'move_items' is not defined                                   no-undef
   483:89   error  'mouseover_window' is not defined                             no-undef
   525:13   error  'open_item' is not defined                                    no-undef
   540:13   error  'open_item' is not defined                                    no-undef
   579:9    error  'update_explorer_footer_selected_items_count' is not defined  no-undef
   596:13   error  'update_explorer_footer_selected_items_count' is not defined  no-undef
   651:34   error  'truncate_filename' is not defined                            no-undef
   651:66   error  'TRUNCATE_LENGTH' is not defined                              no-undef
   661:9    error  'rename_file' is not defined                                  no-undef
   678:13   error  'last_enter_pressed_to_rename_ts' is not defined              no-undef
   679:13   error  'update_explorer_footer_selected_items_count' is not defined  no-undef
   718:25   error  'activate_item_name_editor' is not defined                    no-undef
   763:78   error  'trash_path' is not defined                                   no-undef
   775:29   error  'move_items' is not defined                                   no-undef
   796:25   error  'zipItems' is not defined                                     no-undef
   810:25   error  'zipItems' is not defined                                     no-undef
   875:39   error  'delete_item' is not defined                                  no-undef
   877:63   error  'trash_path' is not defined                                   no-undef
   885:67   error  'trash_path' is not defined                                   no-undef
   885:116  error  'trash_path' is not defined                                   no-undef
   886:69   error  'trash_path' is not defined                                   no-undef
   906:29   error  'create_shortcut' is not defined                              no-undef
   925:25   error  'move_items' is not defined                                   no-undef
   925:53   error  'trash_path' is not defined                                   no-undef
   936:63   error  'trash_path' is not defined                                   no-undef
   936:122  error  'trash_path' is not defined                                   no-undef
   945:25   error  'open_item' is not defined                                    no-undef
   962:49   error  'suggest_apps_for_fsentry' is not defined                     no-undef
   984:37   error  'user_preferences' is not defined                             no-undef
   987:43   error  'user_preferences' is not defined                             no-undef
   989:42   error  'user_preferences' is not defined                             no-undef
  1007:41   error  'user_preferences' is not defined                             no-undef
  1008:72   error  'user_preferences' is not defined                             no-undef
  1011:33   error  'launch_app' is not defined                                   no-undef
  1047:29   error  'open_item' is not defined                                    no-undef
  1093:25   error  'launch_app' is not defined                                   no-undef
  1114:25   error  'empty_trash' is not defined                                  no-undef
  1127:29   error  'zipItems' is not defined                                     no-undef
  1129:29   error  'trigger_download' is not defined                             no-undef
  1140:25   error  'zipItems' is not defined                                     no-undef
  1151:41   error  'JSZip' is not defined                                        no-undef
  1180:25   error  'move_items' is not defined                                   no-undef
  1219:31   error  'clipboard' is not defined                                    no-undef
  1221:28   error  'clipboard_op' is not defined                                 no-undef
  1222:29   error  'copy_clipboard_items' is not defined                         no-undef
  1223:33   error  'clipboard_op' is not defined                                 no-undef
  1224:29   error  'move_clipboard_items' is not defined                         no-undef
  1247:25   error  'create_shortcut' is not defined                              no-undef
  1265:25   error  'move_items' is not defined                                   no-undef
  1265:47   error  'trash_path' is not defined                                   no-undef
  1290:35   error  'delete_item' is not defined                                  no-undef
  1292:63   error  'trash_path' is not defined                                   no-undef
  1299:67   error  'trash_path' is not defined                                   no-undef
  1299:128  error  'trash_path' is not defined                                   no-undef
  1300:57   error  'trash_path' is not defined                                   no-undef
  1313:25   error  'activate_item_name_editor' is not defined                    no-undef
  1373:9    error  'sort_items' is not defined                                   no-undef
  1376:9    error  'activate_item_name_editor' is not defined                    no-undef
  1433:31   error  'copy_to_clipboard' is not defined                            no-undef
  1517:9    error  'show_or_hide_empty_folder_message' is not defined            no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 9fc983f54a chore: Clarify usage of window fields in UIDesktop.js
/puter/src/UI/UIDesktop.js
    44:24   error  'gui_origin' is not defined                                   no-undef
    46:25   error  'auth_token' is not defined                                   no-undef
    86:5    error  'socket' is not defined                                       no-undef
    95:5    error  'socket' is not defined                                       no-undef
   104:5    error  'socket' is not defined                                       no-undef
   105:43   error  'trash_path' is not defined                                   no-undef
   106:45   error  'trash_path' is not defined                                   no-undef
   109:49   error  'trash_path' is not defined                                   no-undef
   112:5    error  'socket' is not defined                                       no-undef
   118:9    error  'launch_apps' is not defined                                  no-undef
   121:9    error  'launch_apps' is not defined                                  no-undef
   121:39   error  'launch_apps' is not defined                                  no-undef
   124:9    error  'launch_apps' is not defined                                  no-undef
   124:30   error  'launch_apps' is not defined                                  no-undef
   127:5    error  'socket' is not defined                                       no-undef
   146:5    error  'socket' is not defined                                       no-undef
   153:85   error  'truncate_filename' is not defined                            no-undef
   153:114  error  'TRUNCATE_LENGTH' is not defined                              no-undef
   156:77   error  'item_icon' is not defined                                    no-undef
   192:13   error  'update_window_path' is not defined                           no-undef
   199:13   error  'sort_items' is not defined                                   no-undef
   203:5    error  'socket' is not defined                                       no-undef
   206:9    error  'sendItemChangeEventToWatchingApps' is not defined            no-undef
   220:25   error  'fsentry.path' is assigned to itself                          no-self-assign
   233:17   error  'update_explorer_footer_item_count' is not defined            no-undef
   234:17   error  'update_explorer_footer_selected_items_count' is not defined  no-undef
   239:26   error  'trash_path' is not defined                                   no-undef
   249:17   error  'update_window_path' is not defined                           no-undef
   253:26   error  'trash_path' is not defined                                   no-undef
   280:25   error  'item_icon' is not defined                                    no-undef
   281:34   error  'trash_path' is not defined                                   no-undef
   287:39   error  'trash_path' is not defined                                   no-undef
   308:37   error  'item_icon' is not defined                                    no-undef
   319:17   error  'sort_items' is not defined                                   no-undef
   324:13   error  'sort_items' is not defined                                   no-undef
   328:5    error  'socket' is not defined                                       no-undef
   333:9    error  'refresh_user_data' is not defined                            no-undef
   336:5    error  'socket' is not defined                                       no-undef
   341:9    error  'refresh_user_data' is not defined                            no-undef
   344:5    error  'socket' is not defined                                       no-undef
   346:9    error  'sendItemChangeEventToWatchingApps' is not defined            no-undef
   360:85   error  'truncate_filename' is not defined                            no-undef
   360:114  error  'TRUNCATE_LENGTH' is not defined                              no-undef
   363:77   error  'item_icon' is not defined                                    no-undef
   398:13   error  'update_window_path' is not defined                           no-undef
   405:13   error  'sort_items' is not defined                                   no-undef
   409:5    error  'socket' is not defined                                       no-undef
   415:9    error  'sendItemChangeEventToWatchingApps' is not defined            no-undef
   440:81   error  'item_icon' is not defined                                    no-undef
   445:17   error  'sort_items' is not defined                                   no-undef
   455:29   error  'item_icon' is not defined                                    no-undef
   463:17   error  Duplicate key 'associated_app_name'                           no-dupe-keys
   470:17   error  'sort_items' is not defined                                   no-undef
   491:42   error  'desktop_path' is not defined                                 no-undef
   496:5    error  'getItem' is not defined                                      no-undef
   508:8    error  'url_query_params' is not defined                             no-undef
   525:9    error  'update_user_preferences' is not defined                      no-undef
   560:17   error  'upload_items' is not defined                                 no-undef
   560:52   error  'desktop_path' is not defined                                 no-undef
   577:16   error  'mouseover_window' is not defined                             no-undef
   585:69   error  'desktop_path' is not defined                                 no-undef
   613:17   error  'copy_items' is not defined                                   no-undef
   613:43   error  'desktop_path' is not defined                                 no-undef
   617:17   error  'move_items' is not defined                                   no-undef
   617:43   error  'desktop_path' is not defined                                 no-undef
   649:39   error  'is_auto_arrange_enabled' is not defined                      no-undef
   651:37   error  'is_auto_arrange_enabled' is not defined                      no-undef
   651:64   error  'is_auto_arrange_enabled' is not defined                      no-undef
   652:37   error  'store_auto_arrange_preference' is not defined                no-undef
   652:67   error  'is_auto_arrange_enabled' is not defined                      no-undef
   653:40   error  'is_auto_arrange_enabled' is not defined                      no-undef
   654:41   error  'sort_items' is not defined                                   no-undef
   655:41   error  'set_sort_by' is not defined                                  no-undef
   656:41   error  'clear_desktop_item_positions' is not defined                 no-undef
   658:41   error  'set_desktop_item_positions' is not defined                   no-undef
   668:44   error  'is_auto_arrange_enabled' is not defined                      no-undef
   671:37   error  'sort_items' is not defined                                   no-undef
   672:37   error  'set_sort_by' is not defined                                  no-undef
   677:44   error  'is_auto_arrange_enabled' is not defined                      no-undef
   680:37   error  'sort_items' is not defined                                   no-undef
   681:37   error  'set_sort_by' is not defined                                  no-undef
   686:44   error  'is_auto_arrange_enabled' is not defined                      no-undef
   689:37   error  'sort_items' is not defined                                   no-undef
   690:37   error  'set_sort_by' is not defined                                  no-undef
   695:44   error  'is_auto_arrange_enabled' is not defined                      no-undef
   698:37   error  'sort_items' is not defined                                   no-undef
   699:37   error  'set_sort_by' is not defined                                  no-undef
   708:44   error  'is_auto_arrange_enabled' is not defined                      no-undef
   712:37   error  'sort_items' is not defined                                   no-undef
   713:37   error  'set_sort_by' is not defined                                  no-undef
   718:44   error  'is_auto_arrange_enabled' is not defined                      no-undef
   722:37   error  'sort_items' is not defined                                   no-undef
   723:37   error  'set_sort_by' is not defined                                  no-undef
   757:43   error  'desktop_path' is not defined                                 no-undef
   767:35   error  'clipboard' is not defined                                    no-undef
   769:32   error  'clipboard_op' is not defined                                 no-undef
   770:33   error  'copy_clipboard_items' is not defined                         no-undef
   770:54   error  'desktop_path' is not defined                                 no-undef
   771:37   error  'clipboard_op' is not defined                                 no-undef
   772:33   error  'move_clipboard_items' is not defined                         no-undef
   780:35   error  'actions_history' is not defined                              no-undef
   782:29   error  'undo_last_action' is not defined                             no-undef
   791:29   error  'init_upload_using_dialog' is not defined                     no-undef
   818:9    error  'is_embedded' is not defined                                  no-undef
   911:12   error  'user' is not defined                                         no-undef
   922:13   error  'is_embedded' is not defined                                  no-undef
   940:8    error  'url_query_params' is not defined                             no-undef
   941:28   error  'url_query_params' is not defined                             no-undef
   943:35   error  'home_path' is not defined                                    no-undef
   944:16   error  'url_query_params' is not defined                             no-undef
   945:34   error  'url_query_params' is not defined                             no-undef
   950:29   error  'item_icon' is not defined                                    no-undef
   966:13   error  'launch_app' is not defined                                   no-undef
   967:23   error  'app_launched_from_url' is not defined                        no-undef
   970:25   error  'app_query_params' is not defined                             no-undef
  1017:40   error  'taskbar_height' is not defined                               no-undef
  1023:40   error  'user' is not defined                                         no-undef
  1024:9    error  'getItem' is not defined                                      no-undef
  1031:21   error  'setItem' is not defined                                      no-undef
  1125:47   error  'user' is not defined                                         no-undef
  1128:48   error  'user' is not defined                                         no-undef
  1131:25   error  'update_auth_data' is not defined                             no-undef
  1170:37   error  'listSupportedLanguages' is not defined                       no-undef
  1249:29   error  'logout' is not defined                                       no-undef
  1253:25   error  'logout' is not defined                                       no-undef
  1261:9    error  'is_fullscreen' is not defined                                no-undef
  1308:5    error  'launch_app' is not defined                                   no-undef
  1381:9    error  'launch_apps' is not defined                                  no-undef
  1460:14   error  'api_origin' is not defined                                   no-undef
  1468:40   error  'auth_token' is not defined                                   no-undef
  1488:14   error  'toolbar_height' is not defined                               no-undef
  1502:9    error  'reset_window_size_and_position' is not defined               no-undef
  1513:5    error  'refresh_desktop_background' is not defined                   no-undef
  1520:26   error  'window_border_radius' is not defined                         no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins dd7361441d chore: Clarify usage of window fields in UIContextMenu.js
/puter/src/UI/UIContextMenu.js
   23:21  error  'global_element_id' is not defined      no-undef
  117:57  error  'taskbar_height' is not defined         no-undef
  118:52  error  'taskbar_height' is not defined         no-undef
  260:17  error  'make_taskbar_sortable' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 63347843cb chore: Clarify usage of window fields in UIAlert.js
/puter/src/UI/UIAlert.js
  26:12  error  'isString' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins c2ef0a9578 chore: Clarify usage of window fields in Settings app
Solves these eslint issues:

/puter/src/UI/Settings/UITabAccount.js
  34:13   error  'user' is not defined  no-undef
  47:99   error  'user' is not defined  no-undef
  55:12   error  'user' is not defined  no-undef
  59:105  error  'user' is not defined  no-undef

/puter/src/UI/Settings/UITabLanguage.js
  35:37  error  'listSupportedLanguages' is not defined  no-undef

/puter/src/UI/Settings/UITabUsage.js
   45:18  error  'api_origin' is not defined   no-undef
   50:46  error  'auth_token' is not defined   no-undef
   54:21  error  'logout' is not defined       no-undef
   96:18  error  'api_origin' is not defined   no-undef
  101:46  error  'auth_token' is not defined   no-undef
  105:21  error  'logout' is not defined       no-undef
  116:51  error  'byte_format' is not defined  no-undef
  123:41  error  'byte_format' is not defined  no-undef
  124:45  error  'byte_format' is not defined  no-undef

/puter/src/UI/Settings/UIWindowChangeEmail.js
   96:18  error  'api_origin' is not defined  no-undef
  100:44  error  'auth_token' is not defined  no-undef

/puter/src/UI/Settings/UIWindowFinalizeUserDeletion.js
   29:12  error  'user' is not defined        no-undef
   97:16  error  'user' is not defined        no-undef
  115:22  error  'api_origin' is not defined  no-undef
  120:50  error  'auth_token' is not defined  no-undef
  127:25  error  'logout' is not defined      no-undef
  139:25  error  'logout' is not defined      no-undef

/puter/src/UI/Settings/UIWindowSettings.js
  48:162  error  'icons' is not defined  no-undef
  86:13   error  Duplicate key 'height'  no-dupe-keys
2024-05-02 11:21:50 +01:00
Sam Atkins d17e0b80b3 chore: Add missing import for node:console
Solves these eslint issues:

/puter/run-selfhosted.js
   49:9  error  'console' is not defined  no-undef
   64:5  error  'console' is not defined  no-undef
  127:5  error  'console' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 8d4a1e0ed3 fix: Add missing TextEncoder to PTT
Solves this eslint issue:

/puter/packages/terminal/src/pty/PTT.js
  35:29  error  'encoder' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 280479c0c6 chore: Clarify usage of window fields in IPC.js
Resolves these eslint errors:

/puter/src/IPC.js
    53:69  error  'appCallbackFunctions' is not defined                no-undef
    55:9   error  'appCallbackFunctions' is not defined                no-undef
    57:16  error  'appCallbackFunctions' is not defined                no-undef
    81:33  error  'window_for_app_instance' is not defined             no-undef
    84:27  error  'iframe_for_app_instance' is not defined             no-undef
   105:48  error  Empty block statement                                no-empty
   180:18  error  'api_origin' is not defined                          no-undef
   190:44  error  'auth_token' is not defined                          no-undef
   194:21  error  'logout' is not defined                              no-undef
   207:18  error  'api_origin' is not defined                          no-undef
   216:44  error  'auth_token' is not defined                          no-undef
   220:21  error  'logout' is not defined                              no-undef
   239:18  error  'api_origin' is not defined                          no-undef
   248:44  error  'auth_token' is not defined                          no-undef
   252:21  error  'logout' is not defined                              no-undef
   268:13  error  'is_auth' is not defined                             no-undef
   309:13  error  'is_auth' is not defined                             no-undef
   348:27  error  'window_for_app_instance' is not defined             no-undef
   360:27  error  'window_for_app_instance' is not defined             no-undef
   576:35  error  'uuidv4' is not defined                              no-undef
   582:9   error  'launch_app' is not defined                          no-undef
   597:37  error  'appdata_path' is not defined                        no-undef
   629:12  error  'appdata_signatures' is not defined                  no-undef
   633:23  error  'appdata_signatures' is not defined                  no-undef
   638:30  error  'appdata_path' is not defined                        no-undef
   647:25  error  'appdata_signatures' is not defined                  no-undef
   664:29  error  'appdata_signatures' is not defined                  no-undef
   682:13  error  'is_auth' is not defined                             no-undef
   717:13  error  'is_auth' is not defined                             no-undef
   745:13  error  'is_auth' is not defined                             no-undef
   773:13  error  'is_auth' is not defined                             no-undef
   783:22  error  'api_origin' is not defined                          no-undef
   793:48  error  'auth_token' is not defined                          no-undef
   797:25  error  'logout' is not defined                              no-undef
   825:13  error  'is_auth' is not defined                             no-undef
   857:36  error  'operation_id' is not defined                        no-undef
   872:41  error  'auth_token' is not defined                          no-undef
   873:41  error  'api_origin' is not defined                          no-undef
   939:45  error  'item_icon' is not defined                           no-undef
   951:33  error  'sort_items' is not defined                          no-undef
   954:29  error  'show_save_account_notice_if_needed' is not defined  no-undef
   998:38  error  'busy_indicator_hide_delay' is not defined           no-undef
  1004:33  error  'busy_indicator_hide_delay' is not defined           no-undef
  1018:37  error  'pictures_path' is not defined                       no-undef
  1020:37  error  'desktop_path' is not defined                        no-undef
  1022:37  error  'documents_path' is not defined                      no-undef
  1024:37  error  'videos_path' is not defined                         no-undef
  1026:37  error  'audio_path' is not defined                          no-undef
  1028:37  error  'appdata_path' is not defined                        no-undef
  1032:13  error  'is_auth' is not defined                             no-undef
  1044:28  error  'operation_id' is not defined                        no-undef
  1059:33  error  'auth_token' is not defined                          no-undef
  1060:33  error  'api_origin' is not defined                          no-undef
  1145:31  error  'iframe_for_app_instance' is not defined             no-undef
  1163:31  error  'window_for_app_instance' is not defined             no-undef
  1178:36  error  'get_apps' is not defined                            no-undef
  1199:11  error  'window_for_app_instance' is not defined             no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins ca65ed1258 chore: Use this to refer to itemWatchCallbackFunctions field
Solves these eslint issues:

/puter/packages/puter-js/src/modules/UI.js
  418:20  error  'itemWatchCallbackFunctions' is not defined  no-undef
  418:74  error  'itemWatchCallbackFunctions' is not defined  no-undef
  419:21  error  'itemWatchCallbackFunctions' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 33785b3786 chore: Add missing imports for node:process 2024-05-02 11:21:50 +01:00
Sam Atkins 96e9c154bd chore: Fix a couple of regex related eslint issues
/puter/packages/phoenix/src/puter-shell/providers/ScriptCommandProvider.js
  27:38  error  Unnecessary escape character: \/  no-useless-escape

/puter/packages/phoenix/src/util/wrap-text.js
  24:33  error  Unexpected control character(s) in regular expression: \x1b  no-control-regex
2024-05-02 11:21:50 +01:00
Sam Atkins c8a20cadbf fix: Correct grep output when asking for line numbers
A couple of issues here:
- We didn't pass the line number to do_grep_line() so `i` was undefined
- Operator precedence messed with the ternary so when line numbers were
  requested, the line wouldn't be output.

Found thanks to this now-solved eslint issue:

/puter/packages/phoenix/src/puter-shell/coreutils/grep.js
  100:60  error  'i' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 71f8afab9a chore: Adjust comment for eslint
This was confusing its fallthrough detection:

/puter/packages/phoenix/src/puter-shell/coreutils/date.js
  132:21  error  Expected a 'break' statement before 'case'  no-fallthrough
2024-05-02 11:21:50 +01:00
Sam Atkins 6ad8f5e06a fix: Parse octal echo escapes
Found by this eslint issue:

/puter/packages/phoenix/src/puter-shell/coreutils/coreutil_lib/echo_escapes.js
  107:59  error  'hexchars' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 50d75cd2f9 refactor: Make loop condition non-constant
Resolves this eslint issue:

/puter/packages/phoenix/src/ansi-shell/readline/readline.js
  154:33  error  Unexpected constant condition  no-constant-condition
2024-05-02 11:21:50 +01:00
Sam Atkins 6d895dff42 chore: Remove empty block statement
Resolves this eslint issue:

/puter/packages/phoenix/src/ansi-shell/parsing/PuterShellParser.js
  25:9  error  Empty block statement  no-empty
2024-05-02 11:21:50 +01:00
Sam Atkins d4c2b492ef fix: Correct inverted instanceof check in SignalReader.read()
Also make tmp_value non-const because it gets modified later.

Solves these eslint issues:

/puter/packages/phoenix/src/ansi-shell/ioutil/SignalReader.js
  45:14  error  Unexpected negating the left operand of 'instanceof' operator  no-unsafe-negation
  46:13  error  'tmp_value' is constant                                        no-const-assign
2024-05-02 11:21:50 +01:00
Sam Atkins 64c886bfeb chore: Clarify setter to not return a value
Solves this eslint issue:

/puter/packages/phoenix/src/ansi-shell/ANSIShell.js
  86:23  error  Setter cannot return a value  no-setter-return
2024-05-02 11:21:50 +01:00
Sam Atkins 2094e05a2e chore: Comment out unreachable code in ExpectationService
The `return` looks temporary but I don't know this code well enough.

Solves this eslint issue:

/puter/packages/backend/src/services/runtime-analysis/ExpectationService.js
  94:9  error  Unreachable code  no-unreachable
2024-05-02 11:21:50 +01:00
Sam Atkins 0df0de6507 chore: Define def() and defv() using const
Fixes these eslint issues:

/puter/packages/backend/src/services/auth/TokenService.js
   3:1   error  'def' is not defined   no-undef
  18:1   error  'defv' is not defined  no-undef
  61:11  error  'def' is not defined   no-undef
  69:21  error  'defv' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 01ab6b88ea chore: Remove unused uses of uuid_user in save_account.js
The variable doesn't exist, and we never use it after this. Seems like a
copy-paste error.

Solves these eslint errors:

/puter/packages/backend/src/routers/save_account.js
  90:9   error  'uuid_user' is not defined  no-undef
  91:9   error  'uuid_user' is not defined  no-undef
  91:21  error  'uuid_user' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 9b3dd6b753 chore: Fix eslint issues in backend util
/puter/packages/backend/src/util/stdioutil.js
  26:24  error  Unexpected control character(s) in regular expression: \x1b  no-control-regex

/puter/packages/backend/src/util/streamutil.js
  368:1  error  'string_to_stream' is not defined  no-undef
  463:5  error  'string_to_stream' is not defined  no-undef

/puter/packages/backend/src/util/strutil.js
  42:1  error  'format_as_usd' is not defined  no-undef
  56:5  error  'format_as_usd' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 60523dc7a7 chore: Fix some eslint issues in services
/puter/packages/backend/src/services/ContextInitService.js
  57:18  error  'async_factory' is not defined  no-undef

/puter/packages/backend/src/services/StorageService.js
  22:5  error  Expected to call 'super()'  constructor-super

/puter/packages/backend/src/services/WebServerService.js
  258:35  error  'services' is not defined  no-undef

/puter/packages/backend/src/services/auth/AuthService.js
  52:13  error  Unreachable code  no-unreachable

/puter/packages/backend/src/services/drivers/implementations/BaseImplementation.js
   64:25  error  'services' is not defined  no-undef
   75:39  error  'services' is not defined  no-undef
  117:39  error  'services' is not defined  no-undef
  123:42  error  'services' is not defined  no-undef
  149:42  error  'services' is not defined  no-undef
  168:38  error  'services' is not defined  no-undef

/puter/packages/backend/src/services/drivers/implementations/PuterDriverProxy.js
  43:5  error  Expected to call 'super()'              constructor-super
  44:9  error  'this' is not allowed before 'super()'  no-this-before-super

/puter/packages/backend/src/services/drivers/meta/Construct.js
  125:9  error  Unreachable code  no-unreachable

/puter/packages/backend/src/services/runtime-analysis/PagerService.js
  49:41  error  'util' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins ca3f9a823d chore: Fix some eslint issues in routers
/puter/packages/backend/src/routers/open_item.js
  48:10  error  Unexpected negating the left operand of 'instanceof' operator  no-unsafe-negation

/puter/packages/backend/src/routers/save_account.js
  106:34  error  'get_user' is not defined   no-undef

/puter/packages/backend/src/routers/sign.js
  37:10  error  Unexpected negating the left operand of 'instanceof' operator  no-unsafe-negation
2024-05-02 11:21:50 +01:00
Sam Atkins 0c0846eef9 chore: Fix some backend router eslint issues
/puter/packages/backend/src/routers/auth/list-permissions.js
  36:15  error  'APIError' is not defined  no-undef

/puter/packages/backend/src/routers/auth/list-sessions.js
  17:15  error  'APIError' is not defined  no-undef

/puter/packages/backend/src/routers/auth/revoke-user-app.js
  34:15  error  'APIError' is not defined  no-undef
  43:15  error  'APIError' is not defined  no-undef

/puter/packages/backend/src/routers/delete-site.js
  43:11  error  Unexpected empty object pattern  no-empty-pattern

/puter/packages/backend/src/routers/drivers/usage.js
  146:11  error  'k' is not defined  no-undef
  147:21  error  'k' is not defined  no-undef
  147:52  error  'k' is not defined  no-undef

/puter/packages/backend/src/routers/drivers/xd.js
  68:5  error  'window' is not defined  no-undef
  69:21  error  Parsing error: The keyword 'interface' is reserved

/puter/packages/backend/src/routers/filesystem_api/batch/all.js
   51:21  error  'get_app' is not defined       no-undef
  224:13  error  Unexpected constant condition  no-constant-condition

/puter/packages/backend/src/routers/filesystem_api/copy.js
   70:10  error  Unexpected constant condition  no-constant-condition
  106:13  error  Duplicate key 'new_name'       no-dupe-keys

/puter/packages/backend/src/routers/filesystem_api/read.js
  80:5  error  Unreachable code  no-unreachable

/puter/packages/backend/src/routers/filesystem_api/token-read.js
   53:9  error  Unreachable code  no-unreachable
   58:9  error  Unreachable code  no-unreachable
  104:5  error  Unreachable code  no-unreachable

/puter/packages/backend/src/routers/hosting/puter-site.js
  65:21  error  Unexpected constant nullishness on the left-hand side of a `??` expression  no-constant-binary-expression
2024-05-02 11:21:50 +01:00
Sam Atkins b4af28a91b chore: Miscellaneous eslint fixes
/puter/packages/backend/src/om/entitystorage/ValidationES.js
  89:25  error  Do not assign to the exception parameter  no-ex-assign

/puter/packages/backend/src/om/proptypes/__all__.js
  166:17  warning  Unexpected 'debugger' statement  no-debugger

/puter/packages/backend/src/routers/_default.js
  405:31  error  'err' is not defined  no-undef
2024-05-02 11:21:50 +01:00
Sam Atkins 4879ee93bf chore: Fix eslint errors in backend/src/helpers.js
/puter/packages/backend/src/helpers.js
   682:9   error  'sharing_users' is not defined     no-undef
   689:12  error  'sharing_users' is not defined     no-undef
   690:28  error  'sharing_users' is not defined     no-undef
   695:28  error  'sharing_users' is not defined     no-undef
   720:9   error  'shared_fsentries' is not defined  no-undef
   733:12  error  'shared_fsentries' is not defined  no-undef
   734:28  error  'shared_fsentries' is not defined  no-undef
   735:17  error  'shared_fsentries' is not defined  no-undef
   735:58  error  'shared_fsentries' is not defined  no-undef
   736:31  error  'shared_fsentries' is not defined  no-undef
   900:57  error  'e' is not defined                 no-undef
  1849:18  error  Empty block statement              no-empty
2024-05-02 11:21:50 +01:00
Sam Atkins 8ab1cd0ca8 chore: Remove unused 'connective' source files 2024-05-02 11:21:50 +01:00
Sam Atkins 11f3e29604 chore: Disable eslint checks on puter-js tests
These currently work in a way that's different from what eslint expects,
so disable it. At some point it would be good if it could check them
(and if the tests could run on CI) but right now they just make a lot of
noise.
2024-05-02 11:21:50 +01:00
Sam Atkins 8cf6379de3 chore: Correct eslint errors in backend filesystem
Removes or disables the following eslint errors/warnings:

/puter/packages/backend/src/api/filesystem/FlagParam.js
  33:19  error  'APIError' is not defined  no-undef
  47:19  error  'APIError' is not defined  no-undef
  58:15  error  'APIError' is not defined  no-undef

/puter/packages/backend/src/api/filesystem/StringParam.js
  32:19  error  'APIError' is not defined  no-undef
  39:13  error  'APIError' is not defined  no-undef
  46:19  error  'APIError' is not defined  no-undef

/puter/packages/backend/src/filesystem/FilesystemService.js
  141:17  warning  Unexpected 'debugger' statement  no-debugger
  366:21  error    'services' is not defined        no-undef

/puter/packages/backend/src/filesystem/batch/BatchExecutor.js
  121:21  error  Do not assign to the exception parameter  no-ex-assign

/puter/packages/backend/src/filesystem/hl_operations/hl_data_read.js
  44:19  error  'APIError' is not defined     no-undef
  47:22  error  'chkperm' is not defined      no-undef
  48:19  error  'APIError' is not defined     no-undef
  51:29  error  'LLRead' is not defined       no-undef
  54:13  error  'version_id' is not defined   no-undef
  88:35  error  'PassThrough' is not defined  no-undef

/puter/packages/backend/src/filesystem/hl_operations/hl_mkdir.js
  68:49  error  'fs' is not defined  no-undef

/puter/packages/backend/src/filesystem/hl_operations/hl_move.js
  102:33  error  'get_user' is not defined  no-undef
  104:35  error  'get_user' is not defined  no-undef
  110:33  error  'df' is not defined        no-undef

/puter/packages/backend/src/filesystem/hl_operations/hl_read.js
  54:13  error  'stream' is constant  no-const-assign

/puter/packages/backend/src/filesystem/hl_operations/hl_stat.js
  40:37  error  'APIError' is not defined  no-undef

/puter/packages/backend/src/filesystem/lib/PuterPath.js
  67:5  error  Expected to return a value in getter 'hasRelativePortion'  getter-return

/puter/packages/backend/src/filesystem/ll_operations/ll_copy_idea.js
   53:21  error  'UploadProgressTracker' is not defined   no-undef
   73:17  error  'PuterS3StorageStrategy' is not defined  no-undef
  137:22  error  'LLFilesystemOperation' is not defined   no-undef

/puter/packages/backend/src/filesystem/ll_operations/ll_read.js
  102:65  error  'offset' is not defined  no-undef
  102:73  error  'offset' is not defined  no-undef
  102:80  error  'length' is not defined  no-undef

/puter/packages/backend/src/filesystem/ll_operations/ll_rmnode.js
  43:23  error  'APIError' is not defined  no-undef

/puter/packages/backend/src/filesystem/storage/SystemFSEntryService.js
  101:26  error  '_path' is not defined  no-undef

/puter/packages/backend/src/filesystem/validation.js
  27:29  error  Unexpected control character(s) in regular expression: \x00, \x1f  no-control-regex
  28:29  error  Unexpected control character(s) in regular expression: \x00, \x1f  no-control-regex
  28:31  error  Unnecessary escape character: \/                                   no-useless-escape
2024-05-02 11:21:50 +01:00
Sam Atkins 4a426ce045 chore: Remove duplicate translation keys 2024-05-02 11:21:50 +01:00
Sam Atkins 25b35769c5 chore: Set-up eslint
eslint is a static analysis tool that tries to identify bugs and
mistakes in the code. We have quite a variety of code in this repo so
the config is a little complicated, but I've tried to make it clear.
It's found a *lot* of issues (over 1700), and while many of which will
not be actual problems, (it doesn't like us using window properties
without `window.`,) but some definitely are.
2024-05-02 11:21:50 +01:00
Nariman Jelveh 4b0c474537 Merge pull request #363 from AtkinsSJ/document-selfhost-limitations
docs: Explain self-host differences
2024-05-01 11:09:37 -07:00
Sam Atkins a74b8e32fa docs: Explain self-host differences 2024-04-30 16:29:57 +01:00
Sam Atkins 251368e749 docs: Link to sections in README 2024-04-30 16:29:47 +01:00
Nariman Jelveh 0b1f963f0b Add fun HN badges! 2024-04-30 00:01:36 -07:00
Nariman Jelveh 4ea54823b0 Merge pull request #360 from Bashamega/bashamega-patch
Fixes the scroll bar
2024-04-29 22:20:33 -07:00
Bashamega c6ffa6e9e1 fix 2024-04-30 06:48:11 +03:00
KernelDeimos 8e6ee9ea79 Fix oversight in token compression 2024-04-29 22:48:10 -04:00
KernelDeimos e7e7363fa7 Drop useless header 2024-04-29 22:34:19 -04:00
KernelDeimos 5a76bad28d fix: reduce token lengths 2024-04-29 21:46:02 -04:00
KernelDeimos c1e4eeec32 Add TokenService and test utility 2024-04-29 21:11:31 -04:00
KernelDeimos d2de46edfb fix: increase QR code size 2024-04-29 19:48:01 -04:00
KernelDeimos 04432df554 feat: improve password recovery experience 2024-04-29 19:26:29 -04:00
KernelDeimos c44028f413 refactor: normalize email calls 2024-04-29 17:34:24 -04:00
Nariman Jelveh 8cad610a54 more sanitization, just in case 2024-04-29 14:09:54 -07:00
Nariman Jelveh f807a28e95 bugfix 2024-04-29 12:05:41 -07:00
KernelDeimos 4c1d5a4b6d fix: fix error handling for outdated node versions 2024-04-29 02:42:04 -04:00
Nariman Jelveh ecfbc44a20 safely escape settings strings 2024-04-28 16:02:54 -07:00
Nariman Jelveh 63c81d6fff Update UITabAccount.js 2024-04-27 19:29:44 -07:00
Nariman Jelveh 42d85abfc2 Update WebServerService.js 2024-04-27 19:10:10 -07:00
Nariman Jelveh fd4e2f59dc Update WebServerService.js 2024-04-27 19:03:48 -07:00
Nariman Jelveh 053728a03f Validate the Host header before responding to requests 2024-04-27 18:52:01 -07:00
Nariman Jelveh 92f6c8003b Merge pull request #352 from enweazudaniel/main
Language: Add Igbo translations
2024-04-27 14:49:28 -07:00
Nariman Jelveh 826afd7653 change en to ig for object name 2024-04-27 14:38:18 -07:00
enweazudaniel 0df9519f76 Language: Add Igbo 2024-04-27 12:06:29 +01:00
enweazudaniel d5d0f67797 Language: Add (Igbo) ig.js 2024-04-27 12:03:18 +01:00
Nariman Jelveh 219cc94fbf Merge branch 'main' of https://github.com/HeyPuter/puter into main 2024-04-26 19:13:34 -07:00
Nariman Jelveh bfa6419070 Update helpers.js 2024-04-26 19:13:22 -07:00
KernelDeimos d7d6ff0cca Rate limit updates 2024-04-26 21:02:01 -04:00
KernelDeimos 79d6f64451 Notify old email when email change is initiated 2024-04-26 21:02:01 -04:00
Nariman Jelveh fd59a6c994 Merge branch 'main' of https://github.com/HeyPuter/puter into main 2024-04-26 15:36:22 -07:00
Nariman Jelveh cb4776cc0e do not append question mark to app URL if there is no query params to append 2024-04-26 15:36:15 -07:00
Eric Dubé 2ee00ca8e6 Revert "fix(security): Prevent email enumeration" (#351) 2024-04-26 18:22:14 -04:00
Nariman Jelveh a3ec7bb5ad Fix the issue with context submenu not closing parent menu when clicked 2024-04-25 23:14:39 -07:00
Nariman Jelveh faa72fd97c Update UIWindow.js 2024-04-25 23:10:03 -07:00
Nariman Jelveh 378b87459a Add robust hostname comparison for when declaring an environment as GUI 2024-04-25 17:51:20 -07:00
KernelDeimos 30f17ade3a fix: use primary read in signup 2024-04-25 19:46:39 -04:00
KernelDeimos ecec8bf75d Use pread for signup page 2024-04-25 19:44:06 -04:00
KernelDeimos 736ebb6f28 Improve server health service 2024-04-25 19:39:18 -04:00
Nariman Jelveh 928dd90f61 Merge pull request #346 from youngsiiimba/main
fix(security): Prevent email enumeration
2024-04-25 14:59:56 -07:00
KernelDeimos eb166a67a9 fix(security): Fix session revocation 2024-04-25 16:19:46 -04:00
Nariman Jelveh 51a6d1ea1d Allow the <p> tag in UIAlert body 2024-04-25 13:19:03 -07:00
Nariman Jelveh 3cce0e88df Revert "Allow the <p> tag in UIAlert body"
This reverts commit e2dcc813ec.
2024-04-25 13:18:37 -07:00
Nariman Jelveh e2dcc813ec Allow the <p> tag in UIAlert body 2024-04-25 13:18:28 -07:00
Nariman Jelveh a572a0a640 Merge pull request #341 from Xiayucheng1212/pass_locale
Pass locale to the iframe url whenever accessing an app
2024-04-25 13:14:16 -07:00
Nariman Jelveh c4b2d9861f Clean up some of the unnecessary console warnings 2024-04-25 13:11:11 -07:00
Simba Chawanda ed70314686 fix(security): Prevent email enumeration 2024-04-25 09:27:37 +02:00
Nariman Jelveh f5f35f2c37 Phase out openItem in IPC
also fix the issue with directories being opened with notepad after setting notepad as default app for files without extensions.
2024-04-24 23:12:57 -07:00
KernelDeimos ccf1afc93c feat(security): add ip rate limiting 2024-04-24 22:35:40 -04:00
KernelDeimos 7800ef6102 fix(security): skip cache when checking old passwd 2024-04-24 22:28:27 -04:00
Nariman Jelveh 25eea41f60 Keep track of app_instance_ids 2024-04-24 17:57:30 -07:00
Nariman Jelveh c21c16026b Update ko.js 2024-04-24 14:43:07 -07:00
KernelDeimos 74e9270d58 Fix 2024-04-24 16:16:31 -04:00
KernelDeimos b2e72adba9 Add ratelimit for /confirm-email 2024-04-24 16:12:09 -04:00
KernelDeimos 1eac147918 Add ratelimit for /contactUs 2024-04-24 16:09:04 -04:00
スーチ・ファトマワティ 3f6f4bb4c0 fix(security): update follow-redirects
When using axios, its dependency follow-redirects only clears authorization header during cross-domain redirect, but allows the proxy-authentication header which contains credentials too.

## Steps To Reproduce & PoC
```js
const axios = require('axios');

axios.get('http://127.0.0.1:10081/', {
 headers: {
 'AuThorization': 'Rear Test',
 'ProXy-AuthoriZation': 'Rear Test',
 'coOkie': 't=1'
 }
})
 .then((response) => {
 console.log(response);
 })
```
When I meet the cross-domain redirect, the sensitive headers like authorization and cookie are cleared, but proxy-authentication header is kept.

```diff
- removeMatchingHeaders(/^(?:authorization|cookie)$/i, this._options.headers);
+ removeMatchingHeaders(/^(?:authorization|proxy-authorization|cookie)$/i, this._options.headers);
```
CWE-200
`CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N`
CVE-2024-28849
2024-04-24 15:23:47 -04:00
Sam Atkins a8d1d3b87a docs: Add help text to dcall utility (#335) 2024-04-24 15:21:31 -04:00
Nariman Jelveh fb3dfc5672 Merge branch 'main' of https://github.com/HeyPuter/puter into main 2024-04-24 12:06:16 -07:00
Nariman Jelveh cdd0231a76 translation fix 2024-04-24 12:06:05 -07:00
Eric Dubé e9e43c059a Merge pull request #342 from brhahlen/docker-ci-improvements
Update Docker CI
2024-04-24 15:04:29 -04:00
Nariman Jelveh 548e975cac remove unused imports, sanitization, and validation of input 2024-04-24 10:05:53 -07:00
Sam Atkins cf0eee1fa3 feat: Add command names to phoenix tab-completion
Gives CommandProviders a `complete(query, {ctx})` method where they can provide completed command names, and then make use of this in CommandCompleter.

Supported CommandProvider sources:
- Shell built-ins (was supported previously)
- PATH executables (when running under Node)
- Puter app names (when running in Puter)

Script filenames are not yet supported.
2024-04-24 15:08:54 +01:00
Sam Atkins dc5b010d09 feat: Allow querying puter-apps driver by partial app names 2024-04-24 15:08:54 +01:00
Sam Atkins a854a0dc0a feat: Implement 'Like' predicate in entity storage
This acts like the SQL 'LIKE' keyword, allowing partial string matches.
2024-04-24 15:08:54 +01:00
Sam Atkins d733119456 fix: Make PathCommandProvider reject queries with path separators
`../bin/foo` should only find `foo` relative to the current working
directory, not to directories in PATH.

Also switch to using the Node path library since PathCommandProvider is
Node-only, and this means getting the correct path separator and
delimiter values on Windows.
2024-04-24 11:45:21 +01:00
Sam Atkins 670673ab8d Rename FooCompleter js files to match FooCommandProvider file names 2024-04-24 11:19:25 +01:00
Ben Hählen 028b37b9d4 Update Docker CI 2024-04-24 11:29:44 +02:00
Xiayucheng1212 916e1bb95c Add local to url 2024-04-24 16:40:42 +08:00
Nariman Jelveh c9e8207e4b Clean up the console warninf message 2024-04-23 23:53:15 -07:00
Nariman Jelveh aef6df048c allow the <strong> tag in UIAlert 2024-04-23 23:06:04 -07:00
Nariman Jelveh f8b2b18185 Update en.js 2024-04-23 22:49:16 -07:00
Nariman Jelveh ce411ed728 Perform more advanced input and string sanitization and validation for performance and security 2024-04-23 22:46:33 -07:00
Nariman Jelveh 9859a32e15 Deprecate and remove UIWindowConfirmDownload 2024-04-23 16:35:28 -07:00
Nariman Jelveh 3be7af8fb8 Merge branch 'main' of https://github.com/HeyPuter/puter into main 2024-04-23 16:26:07 -07:00
Nariman Jelveh 5538649125 Update UIAlert.js 2024-04-23 16:25:57 -07:00
Eric Dubé 97ee951b1f Merge pull request #339 from HeyPuter/eric/rate-limits
Add ip rate limiting to some endpoints
2024-04-23 19:24:17 -04:00
KernelDeimos 44aac16991 Add ip rate limiting 2024-04-23 19:13:37 -04:00
Nariman Jelveh ab5fee1562 deprecate UIWindowGetCopyLink as it's not supported by the backend 2024-04-23 15:43:55 -07:00
KernelDeimos 65a73b5b45 Rename workspace modules to avoid confusion 2024-04-23 04:06:15 -04:00
KernelDeimos 74e213a534 fix(security): always use application/octet-stream 2024-04-22 23:54:03 -04:00
KernelDeimos f9d561d40b docs: document purpose of scary-looking token 2024-04-22 23:48:45 -04:00
Nariman Jelveh 5066128c72 Merge pull request #329 from Eric-Lighthall/desktop-bg-revert
feat: add option to change desktop background to default
2024-04-22 20:26:39 -07:00
Eric Dubé a2de5e3da2 Merge pull request #328 from HeyPuter/release-please--branches--main--components--puter.com
chore(main): release 2.2.0
2024-04-22 22:05:35 -04:00
github-actions[bot] 458f2eae4c chore(main): release 2.2.0 2024-04-23 02:03:34 +00:00
KernelDeimos c166560ff4 feat: add /healthcheck endpoint 2024-04-22 22:02:40 -04:00
Eric Lighthall 03f05f316f feat: add option to change desktop background to default
users can now select 'default' as their desktop background
2024-04-22 18:26:15 -07:00
Eric DubéandNariman Jelveh 331d9e7542 feat: allow apps to add a menubar via puter.js
* Begin work on menubar and dropdowns

* Improve menubar

* Fix pointer event behavior

* Fix labels

* Fix active button

* Eliminate flicker

* Update _default.js

---------

Co-authored-by: Nariman Jelveh <[email protected]>
2024-04-22 20:38:16 -04:00
Eric Dubé ec31007c4b Update main.yml 2024-04-22 19:23:03 -04:00
Eric Dubé e615c7ee7f Update main.yml 2024-04-22 19:15:59 -04:00
Eric Dubé 35d4d4f755 Update main.yml 2024-04-22 19:14:21 -04:00
Eric Dubé 195468c4e1 Update main.yml 2024-04-22 19:11:51 -04:00
Eric Dubé 15f274e662 Create main.yml 2024-04-22 19:06:59 -04:00
310 changed files with 11264 additions and 5378 deletions

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
# === FOR EMPTY COMMITS ===
# Select reason for empty commit:
- [ ] Add conventional commit message for changelog
- [x] Forgot to use conventional commit style
# Increment this value if nothing above was changed
0
+1 -1
View File
@@ -1 +1 @@
PORT=4000
PORT=4000
+10 -12
View File
@@ -5,8 +5,10 @@ name: Docker Image CI
# branch called `main`.
on:
push:
branches: ['release']
tags:
- '*.*.*'
# branches:
# - 'release'
# Defines two custom environment variables for the workflow. These are used
# for the Container registry domain, and a name for the Docker image that
@@ -40,8 +42,8 @@ jobs:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
@@ -56,16 +58,10 @@ jobs:
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
images: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
tags: |
type=schedule
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
type=sha
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
# This step uses the `docker/build-push-action` action to build the
# image, based on your repository's `Dockerfile`. If the build succeeds,
@@ -81,6 +77,8 @@ jobs:
with:
platforms: linux/amd64,linux/arm64
context: .
push: true
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
@@ -1,6 +1,6 @@
# This workflow runs the tools/check-translations.js script to make sure that the translation data is valid.
# Lint PRs and pushes to the main branch
name: Check Translations
name: Lint
env:
NODE_VERSION: 21.x
@@ -13,7 +13,7 @@ on:
branches: [ "main" ]
jobs:
test:
build:
runs-on: ubuntu-latest
steps:
@@ -24,5 +24,10 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: ./package-lock.json
- run: npm ci
- run: npm run check-translations
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npx eslint
- name: Check translations
if: '!cancelled()'
run: npm run check-translations
+40
View File
@@ -0,0 +1,40 @@
name: Maintain Release Merge PR
on:
push:
branches:
- main
jobs:
update-release-pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Git
run: |
git config user.name github-actions
git config user.email [email protected]
- name: Check for existing PR
id: find-pr
uses: juliangruber/find-pull-request-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
branch: release
- uses: actions/checkout@v4
if: steps.find-pr.outputs.number == ''
with:
ref: release
- name: Reset release branch
if: steps.find-pr.outputs.number == ''
run: |
git fetch origin main:main
git reset --hard main
- name: Create/Update PR
if: steps.find-pr.outputs.number == ''
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update release branch
title: Merge Release Auto-PR
body: Merging this PR will invoke release actions
branch: auto-update/release
+17 -1
View File
@@ -1,12 +1,28 @@
# Misc
.DS_Store
# Dependencies
node_modules/
*.zip
*.tgz
license.config.json
license-header.txt
# Build Outputs
dist/
.vscode/
# VS Code IDE
.vscode/**/*
!.vscode/extensions.json
!.vscode/launch.json
!.vscode/settings.json
!.vscode/tasks.json
# Local env files
.env
!.env.example
# this is for jetbrain IDEs
.idea/
/puter
+7
View File
@@ -0,0 +1,7 @@
{
"cSpell.words": [
"dnsmasq",
"heyputer",
"Puter"
]
}
+57
View File
@@ -1,5 +1,62 @@
# Changelog
## 2.3.0 (2024-05-22)
### Features
* add /healthcheck endpoint ([c166560](https://github.com/HeyPuter/puter/commit/c166560ff4ab5a453d3ec4f97326c995deb7f522))
* Add command names to phoenix tab-completion ([cf0eee1](https://github.com/HeyPuter/puter/commit/cf0eee1fa35328e05aefc8a425b5977efe5f4ec9))
* add option to change desktop background to default ([03f05f3](https://github.com/HeyPuter/puter/commit/03f05f316f11e8afe5fcee40b2b80a0de5e6826f))
* allow apps to add a menubar via puter.js ([331d9e7](https://github.com/HeyPuter/puter/commit/331d9e75428ec7609394f59b1755374c7340f83e))
* Allow querying puter-apps driver by partial app names ([dc5b010](https://github.com/HeyPuter/puter/commit/dc5b010d0913d2151b4851f8da5df72d2c8f42e7))
* Display upload errors in UIWindowProgress dialog ([edebbee](https://github.com/HeyPuter/puter/commit/edebbee9e7e9efbb33bf709b637c103be40d15a8))
* Implement 'Like' predicate in entity storage ([a854a0d](https://github.com/HeyPuter/puter/commit/a854a0dc0aa79a31695db833184c5ca3698632a9))
* improve password recovery experience ([04432df](https://github.com/HeyPuter/puter/commit/04432df5540811710ce1cc47ce6c136e5453bccb))
* **security:** add ip rate limiting ([ccf1afc](https://github.com/HeyPuter/puter/commit/ccf1afc93c24ee7f9a126216209a185d6b4d9fe4))
* Show "Deleting /foo" in progress window when deleting files ([f07c13a](https://github.com/HeyPuter/puter/commit/f07c13a50cee790eec44bce2f6e56fbcbf73f9b0))
### Bug Fixes
* Add missing file extension to 0009_app-prefix-fix.sql in DB init ([a8160a8](https://github.com/HeyPuter/puter/commit/a8160a8cdcdd6aff98728a6f1643d93386e6bb5a))
* Add missing TextEncoder to PTT ([8d4a1e0](https://github.com/HeyPuter/puter/commit/8d4a1e0ed3872e2c82b9e4be9b6d8b359e9cea09))
* Correct APIError imports ([062e23b](https://github.com/HeyPuter/puter/commit/062e23b5c9673db1f8b0ff0469289d52dd1e3f99))
* Correct grep output when asking for line numbers ([c8a20ca](https://github.com/HeyPuter/puter/commit/c8a20cadbfd539d185d32f4558916825fcf265ba))
* Correct inverted instanceof check in SignalReader.read() ([d4c2b49](https://github.com/HeyPuter/puter/commit/d4c2b492ef4864804776d3cb7d24797fdc536886))
* Correct variables used in errors in sign.js ([fa7c6be](https://github.com/HeyPuter/puter/commit/fa7c6bee9699527028be0ae9759155bc67c52324))
* Eliminates duplicate translation keys ([5800350](https://github.com/HeyPuter/puter/commit/5800350b253994dea410afff64e3df2a171e7775))
* fix error handling for outdated node versions ([4c1d5a4](https://github.com/HeyPuter/puter/commit/4c1d5a4b6d009ce075897d499d3517219bd745a4))
* Fix phoenix app prefix and TokenService test ([afb9d86](https://github.com/HeyPuter/puter/commit/afb9d866b5091058711db931cde904947e661c15))
* increase QR code size ([d2de46e](https://github.com/HeyPuter/puter/commit/d2de46edfbc05d132d5c929f6935b82515fbbda0))
* Make PathCommandProvider reject queries with path separators ([d733119](https://github.com/HeyPuter/puter/commit/d73311945610417a1ebc7bb0723ced0a599594b4))
* Make url variable accessible to all users of it ([2f30ae7](https://github.com/HeyPuter/puter/commit/2f30ae7a825adcd8da95888c38fe39c34acee0ff))
* Only run Component initialization functions once ([5b43358](https://github.com/HeyPuter/puter/commit/5b43358219402bee3eadf4a0f184a4b924d3293b))
* Parse octal echo escapes ([6ad8f5e](https://github.com/HeyPuter/puter/commit/6ad8f5e06abd050d319271f818d72debf5bc8e44))
* reduce token lengths ([5a76bad](https://github.com/HeyPuter/puter/commit/5a76bad28dfd8ec89a309941e410a54927fae22d))
* reliability issue :bug: ([1d546d9](https://github.com/HeyPuter/puter/commit/1d546d9ef70ef9066ad5838e9782ae330d289f29))
* Remove null or duplicate app entries from suggest_app_for_fsentry() ([6900233](https://github.com/HeyPuter/puter/commit/6900233c5aaa2d1a49f495e9f9a060796757a91e))
* **security:** always use application/octet-stream ([74e213a](https://github.com/HeyPuter/puter/commit/74e213a534dbf2844c8cebeee7eb59ec70de306e))
* **security:** Fix session revocation ([eb166a6](https://github.com/HeyPuter/puter/commit/eb166a67a9f0caf4fd77f9e27dc8209c2fc51f4c))
* **security:** Move token for socket.io to request body ([49b257e](https://github.com/HeyPuter/puter/commit/49b257ecffbb1e12090b86a67528a5ad09da69db))
* **security:** Prevent email enumeration ([ed70314](https://github.com/HeyPuter/puter/commit/ed703146863f896df76c98fad7127c6748c0ef9b))
* **security:** skip cache when checking old passwd ([7800ef6](https://github.com/HeyPuter/puter/commit/7800ef61029c8d1ba47491b4028a0cb972298725))
* **Terminal:** Accept input from Chrome on Android ([4ef3e53](https://github.com/HeyPuter/puter/commit/4ef3e53de34f0097950a7e707ca2483863beafb5))
* test release-please action [#3](https://github.com/HeyPuter/puter/issues/3) ([8fb0a66](https://github.com/HeyPuter/puter/commit/8fb0a66ef21921990e564e5f61c0e80e7f929dc7))
* test release-please action [#4](https://github.com/HeyPuter/puter/issues/4) ([f392de7](https://github.com/HeyPuter/puter/commit/f392de722a5232b622ed91b656a31cdc443c2e84))
* typographical error :bug: ([2949f71](https://github.com/HeyPuter/puter/commit/2949f71691eb0a258888c5d2a5bb496d2fe64a23))
* typographical errors :bug: ([4d30740](https://github.com/HeyPuter/puter/commit/4d30740198402cd1cc61b9ea4c45e006b69ec87e))
* Use correct variable for version number ([52d5299](https://github.com/HeyPuter/puter/commit/52d52993744dffa9f7f59a232da5df9077560731))
* use primary read in signup ([30f17ad](https://github.com/HeyPuter/puter/commit/30f17ade3a893d2283316e581836607e2029f9b9))
## [2.2.0](https://github.com/HeyPuter/puter/compare/v2.1.1...v2.2.0) (2024-04-23)
### Features
* add /healthcheck endpoint ([c166560](https://github.com/HeyPuter/puter/commit/c166560ff4ab5a453d3ec4f97326c995deb7f522))
* allow apps to add a menubar via puter.js ([331d9e7](https://github.com/HeyPuter/puter/commit/331d9e75428ec7609394f59b1755374c7340f83e))
## [2.1.1](https://github.com/HeyPuter/puter/compare/v2.1.0...v2.1.1) (2024-04-22)
+15 -1
View File
@@ -31,7 +31,7 @@ Puter is an advanced, open-source internet operating system designed to be featu
## Getting Started
After reading this section, please proceed to **Self-Hosting** and **Configuration** below.
After reading this section, please proceed to [**Self-Hosting**](#%EF%B8%8F-self-hosting-%EF%B8%8F) and [**Configuration**](#configuration) below.
Read these instructions carefully or you may see errors due to
an invalid setup.
@@ -40,6 +40,7 @@ an invalid setup.
```bash
git clone https://github.com/HeyPuter/puter
cd puter
cp .env.example .env
npm install
npm start
```
@@ -76,6 +77,19 @@ See [Configuration](#configuration) for next steps.
## ⚠️ Self-Hosting ⚠️
The self-hosted version of Puter is currently in alpha stage and should not be used in production yet. It is under active development and may contain bugs, other issues. Please exercise caution and use it for testing and evaluation purposes only.
### Self-Hosting Differences
Currently, the self-hosted version of Puter is different in a few ways from [Puter.com](https://puter.com):
- There is no built-in way to install or create other apps (see below)
- Several "core" apps are missing, such as **Code** or **Draw**, because we can't include them in this repository
- Some icons are different
Work is ongoing to improve the **App Center** and make it available on self-hosted.
Until then, it's possible to add other apps by manually editing the database file.
This process is not recommended unless you know what you are doing.
The file will appear after you first launch Puter, and should be found in `puter/data/puter-database.sqlite` for Docker,
or `volatile/runtime/puter-database.sqlite` otherwise.
You will need a database tool that can understand SQLite databases.
<br/>
## Configuration
+2
View File
@@ -0,0 +1,2 @@
### `vscode`
- `es6-string-html`
+4 -4
View File
@@ -1,4 +1,4 @@
# Configurating Domains for Self-Hosted Puter
# Configuring Domains for Self-Hosted Puter
## Local Network Configuration
@@ -51,7 +51,7 @@ Setting up a local DNS server on your network allows for flexible and scalable d
- **Pi-hole**: Acts as both an ad-blocker and a DNS server. Ideal for easy setup and maintenance.
- **BIND9**: Offers comprehensive DNS server capabilities for complex setups.
- **Dnsmasq**: Lightweight and suitable for smaller networks or those new to running a DNS server.
- **dnsmasq**: Lightweight and suitable for smaller networks or those new to running a DNS server.
**contributors note:** feel free to add any software you're aware of
which might help with this to the list. Also, feel free to add instructions here for specific software; our goal is for Puter to be easy to setup with tools you're already familiar with.
@@ -60,7 +60,7 @@ which might help with this to the list. Also, feel free to add instructions here
1. Choose and install DNS server software on a device within your network.
2. Configure the DNS server to resolve `puter.local` and `api.puter.local` to the IP address of your Puter hosting device.
3. Update your router’s DHCP settings to distribute the DNS server's IP address to all devices on the network.
3. Update your router's DHCP settings to distribute the DNS server's IP address to all devices on the network.
By setting up a local DNS server, you gain the most flexibility and control over your network's domain name resolution, ensuring that all devices can access Puter and its API without manual configuration.
@@ -68,5 +68,5 @@ By setting up a local DNS server, you gain the most flexibility and control over
Please note the self-hosting feature is still in alpha and a public production
deployment is not recommended at this time. However, if you wish to host
publically you can do so following the same steps you normally would to configure
publicly you can do so following the same steps you normally would to configure
a domain name and ensuring the `api` subdomain points to the server as well.
+106
View File
@@ -0,0 +1,106 @@
import js from "@eslint/js";
import globals from "globals";
export default [
js.configs.recommended,
{
// Global ignores
ignores: [
"**/*.min.js",
"**/src/lib/**",
"**/dist/",
"packages/backend/src/public/assets/**",
],
},
{
// Top-level and tools use Node
files: [
"tools/**/*.js",
],
languageOptions: {
globals: {
...globals.node,
}
}
},
{
// Back end
files: [
"packages/backend/**/*.js",
"dev-server.js",
"utils.js",
],
languageOptions: {
globals: {
...globals.node,
"kv": true,
}
}
},
{
// Front end
files: [
"index.js",
"initgui.js",
"src/**/*.js",
"packages/**/*.js",
],
ignores: [
"packages/backend/**/*.js",
],
languageOptions: {
globals: {
...globals.browser,
...globals.commonjs,
"puter": true,
"i18n": true,
"html_encode": true,
"html_decode": true,
"isMobile": true,
// Libraries
"saveAs": true, // FileSaver
"iro": true, // iro.js color picker
"$": true, // jQuery
"jQuery": true, // jQuery
"JSZip": true, // JSZip
"_": true, // lodash
"QRCode": true, // qrcode
"io": true, // socket.io
"timeago": true, // timeago
"SelectionArea": true, // viselect
}
}
},
{
// Tests
files: [
"**/test/**/*.js",
],
languageOptions: {
globals: {
...globals.mocha,
}
}
},
{
// Phoenix
files: [
"packages/phoenix/**/*.js",
],
languageOptions: {
globals: {
...globals.node,
}
}
},
{
// Global rule settings
rules: {
"no-prototype-builtins": "off", // Complains about any use of hasOwnProperty()
"no-unused-vars": "off", // Temporary, we just have a lot of these
"no-debugger": "warn",
"no-async-promise-executor": "off", // We do this quite often and it's fine
}
},
];
+2610 -1772
View File
File diff suppressed because it is too large. Load diff
+4 -1
View File
@@ -1,6 +1,6 @@
{
"name": "puter.com",
"version": "2.1.1",
"version": "2.3.0",
"author": "Puter Technologies Inc.",
"license": "AGPL-3.0-only",
"description": "Desktop environment in the browser!",
@@ -11,10 +11,13 @@
"lib": "lib"
},
"devDependencies": {
"@eslint/js": "^9.1.1",
"chalk": "^4.1.0",
"clean-css": "^5.3.2",
"dotenv": "^16.4.5",
"eslint": "^9.1.1",
"express": "^4.18.2",
"globals": "^15.0.0",
"html-entities": "^2.3.3",
"nodemon": "^3.1.0",
"uglify-js": "^3.17.4",
@@ -0,0 +1,87 @@
# Puter Backend Boot Sequence
This document describes the boot sequence of Puter's backend.
**Constriction**
- Data structures are created
**Initialization**
- Registries are populated
- Services prepare for next phase
**Consolidation**
- Service event bus receives first event (`boot.consolidation`)
- Services perform coordinated setup behaviors
- Services prepare for next phase
**Activation**
- Blocking listeners of `boot.consolidation` have resolved
- HTTP servers start listening
**Ready**
- Services are informed that Puter is providing service
## Boot Phases
### Construction
Services implement a method called `construct` which initializes members
of an instance. Services do not override the class constructor of
**BaseService**. This makes it possible to use the `new` operator without
invoking a service's constructor behavior during debugging.
The first phase of the boot sequence, "construction", is simply a loop to
call `construct` on all registered services.
The `_construct` override should not:
- call other services
- emit events
### Initialization
At initialization, the `init()` method is called on all services.
The `_init` override can be used to:
- register information with other services, when services don't
need to register this information in a specific sequence.
An example of this is registering commands with CommandService.
- perform setup that is required before the consolidation phase starts.
### Consolidation
Consolidation is a phase where services should emit events that
are related to bringing up the system. For example, WebServerService
('web-server') emits an event telling services to install middlewares,
and later emits an event telling services to install routes.
Consolidation starts when Kernel emits `boot.consolidation` to the
services event bus, which happens after `init()` resolves for all
services.
### Activation
Activation is a phase where services begin listening on external
interfaces. For example, this is when the web server starts listening.
Activation starts when Kernel emits `boot.activation`.
### Ready
Ready is a phase where services are informed that everything is up.
Ready starts when Kernel emits `boot.ready`.
## Events and Asynchronous Execution
The services event bus is implemented so you can `await` a call to `.emit()`.
Event listeners can choose to have blocking behavior by returning a promise.
During emission of a particular event, listeners of this event will not
block each other, but all listeners must resolve before the call to
`.emit()` is resolved. (i.e. `emit` uses `Promise.all`)
## Legacy Services
Some services were implemented before the `BaseService` class - which
implements the `init` method - was created. These services are called
"legacy services" and they are instantiated _after_ initialization but
_before_ consolidation.
+2 -2
View File
@@ -55,8 +55,8 @@ If your answer is the second, you should find a way to
In my experience, the harder I think about the correct way to implement
something, the bigger a mistake I'm going to make; ***unless*** a big part
of the reason I'm thinking so hard is because I want to find a solution
that reduces complexity and has the right maintanence trade-off.
that reduces complexity and has the right maintenance trade-off.
There's no easy solution for this so just keep it in mind; there are some
things we might write 2 times, 3 times, even more times over before we
really get it right and *that's okay*; sometimes part of doing useful work is
doing the useless work that reveals what the useful work is.
doing the useless work that reveals what the useful work is.
+2 -2
View File
@@ -20,7 +20,7 @@ const CoreModule = require("./src/CoreModule.js");
const { Kernel } = require("./src/Kernel.js");
const DatabaseModule = require("./src/DatabaseModule.js");
const LocalDiskStorageModule = require("./src/LocalDiskStorageModule.js");
const SelfhostedModule = require("./src/SelfhostedModule.js");
const SelfHostedModule = require("./src/SelfHostedModule.js");
const PuterDriversModule = require("./src/PuterDriversModule.js");
const { testlaunch } = require("./src/index.js");
const BaseService = require("./src/services/BaseService.js");
@@ -45,5 +45,5 @@ module.exports = {
DatabaseModule,
PuterDriversModule,
LocalDiskStorageModule,
SelfhostedModule,
SelfHostedModule,
};
+4 -3
View File
@@ -6,12 +6,10 @@
"scripts": {
"test": "npx mocha"
},
"workspaces": [
"packages/*"
],
"dependencies": {
"@heyputer/kv.js": "^0.1.3",
"@heyputer/multest": "^0.0.2",
"@heyputer/puter-js-common": "^1.0.0",
"@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-node": "^0.43.0",
"@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0",
@@ -30,11 +28,13 @@
"composite-error": "^1.0.2",
"compression": "^1.7.4",
"cookie-parser": "^1.4.6",
"dedent": "^1.5.3",
"express": "^4.18.2",
"file-type": "^18.5.0",
"form-data": "^4.0.0",
"handlebars": "^4.7.8",
"helmet": "^7.0.0",
"hi-base32": "^0.5.1",
"html-entities": "^2.3.3",
"is-glob": "^4.0.3",
"isbot": "^3.7.1",
@@ -54,6 +54,7 @@
"nodemailer": "^6.9.3",
"on-finished": "^2.4.1",
"openai": "^4.20.1",
"otpauth": "9.2.4",
"prompt-sync": "^4.2.0",
"recursive-readdir": "^2.2.3",
"response-time": "^2.3.2",
@@ -1,7 +1,7 @@
# Puter - Common Javascript Module
This is a small module for javascript which you might call a
"langauge tool"; it adds some behavior to make javascript classes
"language tool"; it adds some behavior to make javascript classes
more flexible, with an aim to avoid any significant complexity.
Each class in this module is best described as an _idea_:
@@ -9,7 +9,7 @@ Each class in this module is best described as an _idea_:
### BasicBase
**BasicBase** is the idea that there should be a common way to
see the inheretence chain of the current instance, and obtain
see the inheritance chain of the current instance, and obtain
merged objects and arrays from static members of these classes.
### TraitBase
@@ -1,5 +1,5 @@
{
"name": "puter-js-common",
"name": "@heyputer/puter-js-common",
"version": "1.0.0",
"description": "",
"main": "index.js",
+22 -3
View File
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { Context } = require('./util/context');
@@ -192,6 +192,27 @@ const install = async ({ services, app }) => {
const { SessionService } = require('./services/SessionService');
services.registerService('session', SessionService);
const { EdgeRateLimitService } = require('./services/abuse-prevention/EdgeRateLimitService');
services.registerService('edge-rate-limit', EdgeRateLimitService);
const { Emailservice } = require('./services/EmailService');
services.registerService('email', Emailservice);
const { TokenService } = require('./services/auth/TokenService');
services.registerService('token', TokenService);
const { OTPService } = require('./services/auth/OTPService');
services.registerService('otp', OTPService);
const { UserProtectedEndpointsService } = require("./services/web/UserProtectedEndpointsService");
services.registerService('__user-protected-endpoints', UserProtectedEndpointsService);
const { AntiCSRFService } = require('./services/auth/AntiCSRFService');
services.registerService('anti-csrf', AntiCSRFService);
const { LockService } = require('./services/LockService');
services.registerService('lock', LockService);
}
const install_legacy = async ({ services }) => {
@@ -203,7 +224,6 @@ const install_legacy = async ({ services }) => {
const { OperationTraceService } = require('./services/OperationTraceService');
const { WSPushService } = require('./services/WSPushService');
const { ReferralCodeService } = require('./services/ReferralCodeService');
const { Emailservice } = require('./services/EmailService');
const { ClientOperationService } = require('./services/ClientOperationService');
const { EngPortalService } = require('./services/EngPortalService');
const { AppInformationService } = require('./services/AppInformationService');
@@ -217,7 +237,6 @@ const install_legacy = async ({ services }) => {
services.registerService('operationTrace', OperationTraceService);
services.registerService('__event-push-ws', WSPushService);
services.registerService('referral-code', ReferralCodeService);
services.registerService('email', Emailservice);
services.registerService('file-cache', FileCacheService);
services.registerService('client-operation', ClientOperationService);
services.registerService('app-information', AppInformationService);
+1 -1
View File
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
class DatabaseModule extends AdvancedBase {
async install (context) {
+4 -15
View File
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { Context } = require('./util/context');
class Kernel extends AdvancedBase {
@@ -152,17 +152,7 @@ class Kernel extends AdvancedBase {
const { services } = this;
await services.ready;
{
const app = services.get('web-server').app;
app.use(async (req, res, next) => {
req.services = services;
next();
});
await services.emit('boot.services-initialized');
await services.emit('install.middlewares.context-aware', { app });
await services.emit('install.routes', { app });
await services.emit('install.routes-gui', { app });
}
await services.emit('boot.consolidation');
// === END: Initialize Service Registry ===
@@ -178,9 +168,8 @@ class Kernel extends AdvancedBase {
});
})();
await services.emit('start.webserver');
await services.emit('ready.webserver');
await services.emit('boot.activation');
await services.emit('boot.ready');
}
}
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
class LocalDiskStorageModule extends AdvancedBase {
async install (context) {
+1 -1
View File
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
class PuterDriversModule extends AdvancedBase {
async install () {}
@@ -1,7 +1,7 @@
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const config = require("./config");
class SelfhostedModule extends AdvancedBase {
class SelfHostedModule extends AdvancedBase {
async install (context) {
const services = context.get('services');
@@ -63,4 +63,4 @@ class SelfhostedModule extends AdvancedBase {
}
}
module.exports = SelfhostedModule;
module.exports = SelfHostedModule;
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
class ThirdPartyDriversModule extends AdvancedBase {
// constructor () {
+42
View File
@@ -220,6 +220,10 @@ module.exports = class APIError {
status: 400,
message: 'Missing fileinfo entry or BLOB for operation.',
},
'invalid_file_metadata': {
status: 400,
message: 'Invalid file metadata.',
},
// Open
'no_suitable_app': {
@@ -319,6 +323,10 @@ module.exports = class APIError {
status: 401,
message: 'This authentication token is not supported here.',
},
'token_expired': {
status: 401,
message: 'Authentication token has expired.',
},
'account_suspended': {
status: 403,
message: 'Account suspended.',
@@ -331,6 +339,40 @@ module.exports = class APIError {
status: 403,
message: 'Attempted to create an access token with no permissions.',
},
'invalid_action': {
status: 400,
message: ({ action }) => `Invalid action: ${quot(action)}.`,
},
'2fa_already_enabled': {
status: 409,
message: '2FA is already enabled.',
},
'2fa_not_configured': {
status: 409,
message: '2FA is not configured.',
},
// protected endpoints
'too_many_requests': {
status: 429,
message: 'Too many requests.',
},
'user_tokens_only': {
status: 403,
message: 'This endpoint must be requested with a user session',
},
'temporary_accounts_not_allowed': {
status: 403,
message: 'Temporary accounts cannot perform this action',
},
'password_required': {
status: 400,
message: 'Password is required.',
},
'password_mismatch': {
status: 403,
message: 'Password does not match.',
},
// Object Mapping
'field_not_allowed_for_create': {
@@ -16,6 +16,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const APIError = require('../../api/APIError');
module.exports = class FlagParam {
constructor (srckey, options) {
this.srckey = srckey;
@@ -16,6 +16,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const APIError = require('../../api/APIError');
module.exports = class StringParam {
constructor (srckey, options) {
this.srckey = srckey;
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { quot } = require("../util/strutil");
const { TechnicalError } = require("../errors/TechnicalError");
const { print_error_help } = require("../errors/error_help_details");
+2
View File
@@ -62,6 +62,8 @@ config.thumb_width = 80;
config.thumb_height = 80;
config.app_max_icon_size = 5*1024*1024;
config.defaultjs_asset_path = '../../';
// config.origin = config.protocol + '://' + config.domain;
// config.api_base_url = config.protocol + '://api.' + config.domain;
// config.social_card = `${config.origin}/assets/img/screenshot.png`;
+1 -1
View File
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { quot } = require("../util/strutil");
class ConfigLoader extends AdvancedBase {
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2024 Puter Technologies Inc.
*
* This file is part of Puter.
*
* Puter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
{
registries: {
type: {
description: 'high-level types'
}
}
}
@@ -27,7 +27,7 @@ const SystemFSEntryService = require('./storage/SystemFSEntryService.js');
const PerformanceMonitor = require('../monitor/PerformanceMonitor.js');
const { NodePathSelector, NodeUIDSelector, NodeInternalIDSelector } = require('./node/selectors.js');
const FSNodeContext = require('./FSNodeContext.js');
const { AdvancedBase } = require('puter-js-common');
const { AdvancedBase } = require('@heyputer/puter-js-common');
const { Context } = require('../util/context.js');
const { simple_retry } = require('../util/retryutil.js');
const APIError = require('../api/APIError.js');
@@ -138,7 +138,6 @@ class FilesystemService extends AdvancedBase {
return permission.startsWith('fs:');
},
checker: async (actor, permission) => {
debugger;
if ( !(actor.type instanceof UserActorType) ) {
return undefined;
}
@@ -363,7 +362,7 @@ class FilesystemService extends AdvancedBase {
[new_path, old_path.length + 1, old_path + '%', user_id]
);
const log = services.get('log-service').create('update_child_paths');
const log = this.services.get('log-service').create('update_child_paths');
log.info(`updated ${old_path} -> ${new_path}`);
monitor.end();
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require('puter-js-common');
const { AdvancedBase } = require('@heyputer/puter-js-common');
const PathResolver = require('../../routers/filesystem_api/batch/PathResolver');
const commands = require('./commands').commands;
const { WorkUnit } = require('../../services/runtime-analysis/ExpectationService');
@@ -118,7 +118,7 @@ class BatchExecutor extends AdvancedBase {
alarm: true,
});
e = APIError.adapt(e);
e = APIError.adapt(e); // eslint-disable-line no-ex-assign
}
// Consume stream if there's a file
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { AsyncProviderTrait } = require("../../traits/AsyncProviderTrait");
const { HLMkdir, QuickMkdir } = require("../hl_operations/hl_mkdir");
const { Context } = require("../../util/context");
@@ -18,6 +18,9 @@
*/
const { stream_to_buffer } = require("../../util/streamutil");
const { HLFilesystemOperation } = require("./definitions");
const { chkperm } = require('../../helpers');
const { LLRead } = require('../ll_operations/ll_read');
const APIError = require('../../api/APIError');
/**
* HLDataRead reads a stream of objects from a file containing structured data.
@@ -38,6 +41,7 @@ class HLDataRead extends HLFilesystemOperation {
const {
fsNode,
version_id,
} = this.values;
if ( ! await fsNode.exists() ) {
@@ -85,6 +89,7 @@ class HLDataRead extends HLFilesystemOperation {
}
_stream_jsonl_lines_to_objects (stream) {
const { PassThrough } = this.modules.stream;
const output_stream = new PassThrough();
(async () => {
for await (const line of stream) {
@@ -63,6 +63,7 @@ class MkTree extends HLFilesystemOperation {
async _run () {
const { values, context } = this;
const fs = context.get('services').get('filesystem');
await this.create_branch_({
parent_node: values.parent || await fs.node(new RootNodeSelector()),
@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const APIError = require("../../api/APIError");
const { chkperm, validate_fsentry_name, is_ancestor_of } = require("../../helpers");
const { chkperm, validate_fsentry_name, is_ancestor_of, df, get_user } = require("../../helpers");
const { LLMove } = require("../ll_operations/ll_move");
const { RootNodeSelector } = require("../node/selectors");
const { HLFilesystemOperation } = require("./definitions");
@@ -41,7 +41,7 @@ class HLRead extends HLFilesystemOperation {
}
const ll_read = new LLRead();
const stream = await ll_read.run({
let stream = await ll_read.run({
fsNode, actor,
version_id,
...(byte_count !== undefined ? {
@@ -19,6 +19,7 @@
const { chkperm } = require("../../helpers");
const { Context } = require("../../util/context");
const { HLFilesystemOperation } = require("./definitions");
const APIError = require('../../api/APIError');
class HLStat extends HLFilesystemOperation {
static MODULES = {
@@ -64,10 +64,6 @@ class PuterPath {
return ! this.isAbsolute();
}
get hasRelativePortion () {
}
get reference () {
if ( this.isAbsolute ) return this.constructor.NULL_UUID;
@@ -30,6 +30,7 @@
- easier to diagnose stuck operations
*/
/* eslint-disable */
const STEPS_COPY_CONTENTS = [
{
@@ -91,7 +91,7 @@ class LLRead extends LLFilesystemOperation {
const context = a.iget('context');
const svc_fileCache = context.get('services').get('file-cache');
const { fsNode } = a.values();
const { fsNode, offset, length } = a.values();
const maybe_buffer = await svc_fileCache.try_get(fsNode, a.log);
if ( maybe_buffer ) {
@@ -19,6 +19,7 @@
const { Context } = require("../../util/context");
const { ParallelTasks } = require("../../util/otelutil");
const { LLFilesystemOperation } = require("./definitions");
const APIError = require("../../api/APIError");
class LLRmNode extends LLFilesystemOperation {
async _run () {
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { id2path } = require("../../helpers");
const { PuterPath } = require("../lib/PuterPath");
@@ -17,6 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { PuterPath } = require("../lib/PuterPath");
const _path = require('path');
// Redis keys:
// <env>:<service>:<class>:<type>:<property>:<id>
@@ -22,10 +22,12 @@ This module contains functions that validate filesystem operations.
*/
/* eslint-disable no-control-regex */
const config = require("../config");
const path_excludes = () => /[\x00-\x1F]/g;
const node_excludes = () => /[\/\x00-\x1F]/g;
const node_excludes = () => /[/\x00-\x1F]/g;
// this characters are not allowed in path names because
// they might be used to trick the user into thinking
+37 -67
View File
@@ -184,7 +184,7 @@ async function id2uuid(id){
const cached = options.cached ?? true;
if ( cached ) {
if ( cached && ! options.force ) {
if (options.username) user = kv.get('users:username:' + options.username);
else if (options.email) user = kv.get('users:email:' + options.email);
else if (options.uuid) user = kv.get('users:uuid:' + options.uuid);
@@ -194,16 +194,18 @@ async function id2uuid(id){
if ( user ) return user;
}
if(options.username)
user = await db.read("SELECT * FROM `user` WHERE `username` = ? LIMIT 1", [options.username]);
else if(options.email)
user = await db.read("SELECT * FROM `user` WHERE `email` = ? LIMIT 1", [options.email]);
else if(options.uuid)
user = await db.read("SELECT * FROM `user` WHERE `uuid` = ? LIMIT 1", [options.uuid]);
else if(options.id)
user = await db.read("SELECT * FROM `user` WHERE `id` = ? LIMIT 1", [options.id]);
else if(options.referral_code)
user = await db.read("SELECT * FROM `user` WHERE `referral_code` = ? LIMIT 1", [options.referral_code]);
if ( ! options.force ) {
if(options.username)
user = await db.read("SELECT * FROM `user` WHERE `username` = ? LIMIT 1", [options.username]);
else if(options.email)
user = await db.read("SELECT * FROM `user` WHERE `email` = ? LIMIT 1", [options.email]);
else if(options.uuid)
user = await db.read("SELECT * FROM `user` WHERE `uuid` = ? LIMIT 1", [options.uuid]);
else if(options.id)
user = await db.read("SELECT * FROM `user` WHERE `id` = ? LIMIT 1", [options.id]);
else if(options.referral_code)
user = await db.read("SELECT * FROM `user` WHERE `referral_code` = ? LIMIT 1", [options.referral_code]);
}
if(!user || !user[0]){
if(options.username)
@@ -679,7 +681,7 @@ const get_descendants_0 = async (path, user, depth, return_thumbnail = false) =>
[user.id]
);
// users that have shared files/dirs with this user
sharing_users = await db.read(
const sharing_users = await db.read(
`SELECT DISTINCT(owner_user_id), user.username
FROM share
INNER JOIN user ON user.id = share.owner_user_id
@@ -717,7 +719,7 @@ const get_descendants_0 = async (path, user, depth, return_thumbnail = false) =>
return [];
// shared files/dirs with this user
shared_fsentries = await db.read(
const shared_fsentries = await db.read(
`SELECT
fsentries.id, fsentries.user_id, fsentries.uuid, fsentries.parent_uid, fsentries.bucket, fsentries.bucket_region,
fsentries.name, fsentries.shortcut_to, fsentries.is_shortcut, fsentries.metadata, fsentries.is_dir, fsentries.modified,
@@ -897,7 +899,7 @@ const get_descendants = async (...args) => {
if ( ! result || ! result[0] ) {
errors.report('id2path.select', {
alarm: true,
message: `no result for ${entry_uid}: ${e.message}`,
message: `no result for ${entry_uid}`,
extra: {
entry_uid,
}
@@ -951,12 +953,12 @@ function cp(source_path, dest_path, user, overwrite, change_name, check_perms =
throw new Error(`legacy copy function called`);
}
isString = function (variable) {
function isString(variable) {
return typeof variable === 'string' || variable instanceof String;
}
// checks to see if given variable is an object
isObject = function (variable) {
function isObject(variable) {
return variable !== null && typeof variable === 'object';
}
@@ -1144,8 +1146,8 @@ async function jwt_auth(req){
else if(req.query && req.query.auth_token)
token = req.query.auth_token;
// Socket
else if(req.handshake && req.handshake.query && req.handshake.query.auth_token)
token = req.handshake.query.auth_token;
else if(req.handshake && req.handshake.auth && req.handshake.auth.auth_token)
token = req.handshake.auth.auth_token;
if(!token || token === 'null')
throw('No auth token found');
@@ -1545,56 +1547,16 @@ async function generate_system_fsentries(user){
}
function send_email_verification_code(email_confirm_code, email){
const nodemailer = require("nodemailer");
// send email notif
let transporter = nodemailer.createTransport({
host: config.smtp_server,
port: config.smpt_port,
secure: true, // STARTTLS
auth: {
user: config.smtp_username,
pass: config.smtp_password,
},
});
transporter.sendMail({
from: '"Puter" [email protected]', // sender address
to: email, // list of receivers
subject: `${hyphenize_confirm_code(email_confirm_code)} is your confirmation code`, // Subject line
html: `<p>Hi there,</p>
<p><strong>${hyphenize_confirm_code(email_confirm_code)}</strong> is your email confirmation code.</p>
<p>Sincerely,</p>
<p>Puter</p>
`,
});
const svc_email = Context.get('services').get('email');
svc_email.send_email({ email }, 'email_verification_code', {
code: hyphenize_confirm_code(email_confirm_code),
})
}
function send_email_verification_token(email_confirm_token, email, user_uuid){
const nodemailer = require("nodemailer");
// send email notif
let transporter = nodemailer.createTransport({
host: config.smtp_server,
port: config.smpt_port,
secure: true, // STARTTLS
auth: {
user: config.smtp_username,
pass: config.smtp_password,
},
});
let link = `${config.origin}/confirm-email-by-token?user_uuid=${user_uuid}&token=${email_confirm_token}`;
transporter.sendMail({
from: '"Puter" [email protected]', // sender address
to: email, // list of receivers
subject: `Please confirm your email`, // Subject line
html: `<p>Hi there,</p>
<p>Please confirm your email address using this link: <strong><a href="${link}">${link}</a></strong>.</p>
<p>Sincerely,</p>
<p>Puter</p>
`,
});
const svc_email = Context.get('services').get('email');
const link = `${config.origin}/confirm-email-by-token?user_uuid=${user_uuid}&token=${email_confirm_token}`;
svc_email.send_email({ email }, 'email_verification_link', { link });
}
async function generate_random_username(){
@@ -1808,7 +1770,15 @@ async function suggest_app_for_fsentry(fsentry, options){
monitor.end();
// return list
return suggested_apps;
return suggested_apps.filter((suggested_app, pos, self) => {
// Remove any null values caused by calling `get_app()` for apps that don't exist.
// This happens on self-host because we don't include `code`, among others.
if (!suggested_app)
return false;
// Remove any duplicate entries
return self.indexOf(suggested_app) === pos;
});
}
function build_item_object(item){
@@ -1847,7 +1817,7 @@ async function get_taskbar_items(user) {
try {
taskbar_items_from_db = JSON.parse(user.taskbar_items);
}catch(e){
// ignore errors
}
}
+1 -1
View File
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { WeakConstructorTrait } = require("../traits/WeakConstructorTrait");
const { Eq, And } = require("./query/query");
const { Entity } = require("./entitystorage/Entity");
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { instance_ } = require("../../monitor/PerformanceMonitor");
const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait");
const { Property } = require("./Property");
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait");
class PropType extends AdvancedBase {
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait");
class Property extends AdvancedBase {
@@ -23,7 +23,7 @@ const { AppUnderUserActorType } = require("../../services/auth/Actor");
const { DB_WRITE } = require("../../services/database/consts");
const { Context } = require("../../util/context");
const { origin_from_url } = require("../../util/urlutil");
const { Eq, Or } = require("../query/query");
const { Eq, Like, Or } = require("../query/query");
const { BaseES } = require("./BaseES");
const uuidv4 = require('uuid').v4;
@@ -34,13 +34,19 @@ class AppES extends BaseES {
const services = this.context.get('services');
this.db = services.get('database').get(DB_WRITE, 'apps');
},
async create_predicate (id) {
async create_predicate (id, ...args) {
if ( id === 'user-can-edit' ) {
return new Eq({
key: 'owner',
value: Context.get('user').id,
});
}
if ( id === 'name-like' ) {
return new Like({
key: 'name',
value: args[0],
});
}
},
async delete (uid, extra) {
const svc_appInformation = this.context.get('services').get('app-information');
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait");
const { Context } = require("../../util/context");
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait");
class Entity extends AdvancedBase {
+18 -2
View File
@@ -16,13 +16,13 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { BaseES } = require("./BaseES");
const APIError = require("../../api/APIError");
const { Entity } = require("./Entity");
const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait");
const { And, Or, Eq, Predicate, Null, PredicateUtil } = require("../query/query");
const { And, Or, Eq, Like, Null, Predicate, PredicateUtil } = require("../query/query");
const { DB_WRITE } = require("../../services/database/consts");
class RawCondition extends AdvancedBase {
@@ -355,6 +355,22 @@ class SQLES extends BaseES {
return new RawCondition({ sql, values });
}
if ( om_query instanceof Like ) {
const key = om_query.key;
let value = om_query.value;
const prop = this.om.properties[key];
value = await prop.sql_reference(value);
const options = prop.descriptor.sql ?? {};
const col_name = options.column_name ?? prop.name;
const sql = `${col_name} LIKE ?`;
const values = [value];
return new RawCondition({ sql, values });
}
}
}
}
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { BaseES } = require("./BaseES");
const APIError = require("../../api/APIError");
@@ -86,6 +86,7 @@ class ValidationES extends BaseES {
} catch ( e ) {
if ( ! (e instanceof APIError) ) {
console.log('THIS IS HAPPENING', e);
// eslint-disable-next-line no-ex-assign
e = APIError.create('field_invalid', null, {
key: prop.name,
converted_from_another_error: true,
+1 -1
View File
@@ -163,7 +163,7 @@ module.exports = {
},
async adapt (value, { descriptor }) {
if ( descriptor.debug ) {
debugger;
debugger; // eslint-disable-line no-debugger
}
if ( ! descriptor.service ) return value;
if ( ! value ) return null;
+11 -1
View File
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait");
class Predicate extends AdvancedBase {
@@ -50,6 +50,15 @@ class Eq extends Predicate {
}
}
class Like extends Predicate {
async check (entity) {
// Convert SQL LIKE pattern to RegExp
// TODO: Support escaping the pattern characters
const regex = new RegExp(this.value.replaceAll('%', '.*').replaceAll('_', '.'), 'i');
return regex.test(await entity.get(this.key));
}
}
Predicate.prototype.and = function (other) {
return new And({ children: [this, other] });
}
@@ -105,4 +114,5 @@ module.exports = {
And,
Or,
Eq,
Like,
};
+24 -10
View File
@@ -26,6 +26,7 @@ const auth = require('../middleware/auth.js');
const { generate_puter_page_html } = require('../temp/puter_page_loader');
const { Context } = require('../util/context');
const { DB_READ } = require('../services/database/consts');
const { PathBuilder } = require('../util/pathutil.js');
let auth_user;
@@ -46,7 +47,7 @@ router.all('*', async function(req, res, next) {
// cloud.js must be accessible globally regardless of subdomain
// --------------------------------------
else if (path === '/cloud.js') {
return res.sendFile(_path.join(__dirname, '../../puter.js/alpha.js'), function (err) {
return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/alpha.js'), function (err) {
if (err && err.statusCode) {
return res.status(err.statusCode).send('Error /cloud.js')
}
@@ -56,14 +57,14 @@ router.all('*', async function(req, res, next) {
// /puter.js/v1 must be accessible globally regardless of subdomain
// --------------------------------------
else if (path === '/puter.js/v1' || path === '/puter.js/v1/') {
return res.sendFile(_path.join(__dirname, '../../puter.js/v1.js'), function (err) {
return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/v1.js'), function (err) {
if (err && err.statusCode) {
return res.status(err.statusCode).send('Error /puter.js')
}
});
}
else if (path === '/puter.js/v2' || path === '/puter.js/v2/') {
return res.sendFile(_path.join(__dirname, '../../puter.js/v2.js'), function (err) {
return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/v2.js'), function (err) {
if (err && err.statusCode) {
return res.status(err.statusCode).send('Error /puter.js')
}
@@ -74,14 +75,14 @@ router.all('*', async function(req, res, next) {
// --------------------------------------
else if( subdomain === 'js'){
if (path === '/v1' || path === '/v1/') {
return res.sendFile(_path.join(__dirname, '../../puter.js/v1.js'), function (err) {
return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/v1.js'), function (err) {
if (err && err.statusCode) {
return res.status(err.statusCode).send('Error /puter.js')
}
});
}
if (path === '/v2' || path === '/v2/') {
return res.sendFile(_path.join(__dirname, '../../puter.js/v2.js'), function (err) {
return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/v2.js'), function (err) {
if (err && err.statusCode) {
return res.status(err.statusCode).send('Error /puter.js')
}
@@ -176,7 +177,7 @@ router.all('*', async function(req, res, next) {
const user = await get_user({uuid: req.query.user_uuid})
// more validation
if(user === undefined || user === null || user === false)
if(!user)
h += '<p style="text-align:center; color:red;">User not found.</p>';
else if(user.unsubscribed === 1)
h += '<p style="text-align:center; color:green;">You are already unsubscribed.</p>';
@@ -208,7 +209,7 @@ router.all('*', async function(req, res, next) {
const {get_user} = require('../helpers')
// get user
const user = await get_user({uuid: req.query.user_uuid})
const user = await get_user({uuid: req.query.user_uuid, force: true})
// more validation
if(user === undefined || user === null || user === false)
@@ -219,6 +220,13 @@ router.all('*', async function(req, res, next) {
h += '<p style="text-align:center; color:red;">invalid token.</p>';
// mark user as confirmed
else{
// If other users have the same unconfirmed email, revoke it
await db.write(
'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?',
[user.email],
);
// update user
await db.write(
"UPDATE `user` SET `email_confirmed` = 1, `requires_email_confirmation` = 0 WHERE id = ?",
[user.id]
@@ -246,6 +254,7 @@ router.all('*', async function(req, res, next) {
// /assets/
// ------------------------
else if (path.startsWith('/assets/')) {
path = PathBuilder.resolve(path);
return res.sendFile(path, { root: __dirname + '../../public' }, function (err) {
if (err && err.statusCode) {
return res.status(err.statusCode).send('Error /public/')
@@ -338,7 +347,7 @@ router.all('*', async function(req, res, next) {
// /dist/...
else if(path.startsWith('/dist/') || path.startsWith('/src/')){
path = _path.resolve(path);
path = PathBuilder.resolve(path);
return res.sendFile(path, {root: config.assets.gui}, function(err){
if(err && err.statusCode){
return res.status(err.statusCode).send('Error /gui/dist/')
@@ -348,6 +357,7 @@ router.all('*', async function(req, res, next) {
// All other paths
else{
path = PathBuilder.resolve(path);
return res.sendFile(path, {root: _path.join(config.assets.gui, 'src')}, function(err){
if(err && err.statusCode){
return res.status(err.statusCode).send('Error /gui/')
@@ -364,7 +374,11 @@ router.all('*', async function(req, res, next) {
subdomain === 'draw' || subdomain === 'camera' || subdomain === 'recorder' ||
subdomain === 'dev-center' || subdomain === 'terminal'){
let root = _path.join(__dirname, '../../apps/', subdomain);
let root = PathBuilder
.add(__dirname)
.add(config.defaultjs_asset_path, { allow_traversal: true })
.add('apps').add(subdomain)
.build();
if ( subdomain === 'docs' ) root += '/dist';
root = _path.normalize(root);
@@ -402,7 +416,7 @@ router.all('*', async function(req, res, next) {
});
} catch (e) {
console.error('error from sendFile', e);
return res.status(err.statusCode).send('Error /apps/')
return res.status(e.statusCode).send('Error /apps/')
}
}
// --------------------------------------
@@ -0,0 +1,123 @@
const APIError = require("../../api/APIError");
const eggspress = require("../../api/eggspress");
const { get_user } = require("../../helpers");
const { UserActorType } = require("../../services/auth/Actor");
const { DB_WRITE } = require("../../services/database/consts");
const { Context } = require("../../util/context");
module.exports = eggspress('/auth/configure-2fa/:action', {
subdomain: 'api',
auth2: true,
allowedMethods: ['POST'],
}, async (req, res, next) => {
const action = req.params.action;
const x = Context.get();
// Only users can configure 2FA
const actor = Context.get('actor');
if ( ! (actor.type instanceof UserActorType) ) {
throw APIError.create('forbidden');
}
const user = actor.type.user;
const actions = {};
const db = await x.get('services').get('database').get(DB_WRITE, '2fa');
actions.setup = async () => {
const user = await get_user({ id: req.user.id, force: true });
if ( user.otp_enabled ) {
throw APIError.create('2fa_already_enabled');
}
const svc_otp = x.get('services').get('otp');
// generate secret
const result = svc_otp.create_secret(user.username);
// generate recovery codes
result.codes = [];
for ( let i = 0; i < 10; i++ ) {
result.codes.push(svc_otp.create_recovery_code());
}
const hashed_recovery_codes = result.codes.map(code => {
const crypto = require('crypto');
const hash = crypto
.createHash('sha256')
.update(code)
.digest('base64')
// We're truncating the hash for easier storage, so we have 128
// bits of entropy instead of 256. This is plenty for recovery
// codes, which have only 48 bits of entropy to begin with.
.slice(0, 22);
return hash;
});
// update user
await db.write(
`UPDATE user SET otp_secret = ?, otp_recovery_codes = ? WHERE uuid = ?`,
[result.secret, hashed_recovery_codes.join(','), user.uuid]
);
req.user.otp_secret = result.secret;
req.user.otp_recovery_codes = hashed_recovery_codes.join(',');
user.otp_secret = result.secret;
user.otp_recovery_codes = hashed_recovery_codes.join(',');
return result;
};
// IMPORTANT: only use to verify the user's 2FA setup;
// this should never be used to verify the user's 2FA code
// for authentication purposes.
actions.test = async () => {
const user = req.user;
const svc_otp = x.get('services').get('otp');
const code = req.body.code;
const ok = svc_otp.verify(user.username, user.otp_secret, code);
return { ok };
};
actions.enable = async () => {
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('enable-2fa') ) {
return res.status(429).send('Too many requests.');
}
const user = await get_user({ id: req.user.id, force: true });
// Verify that 2FA isn't already enabled
if ( user.otp_enabled ) {
throw APIError.create('2fa_already_enabled');
}
// Verify that TOTP secret was set (configuration step not skipped)
if ( ! user.otp_secret ) {
throw APIError.create('2fa_not_configured');
}
await db.write(
`UPDATE user SET otp_enabled = 1 WHERE uuid = ?`,
[user.uuid]
);
// update cached user
req.user.otp_enabled = 1;
const svc_email = req.services.get('email');
await svc_email.send_email({ email: user.email }, 'enabled_2fa', {
username: user.username,
});
return {};
};
if ( ! actions[action] ) {
throw APIError.create('invalid_action', null, { action });
}
const result = await actions[action]();
res.json(result);
});
@@ -21,6 +21,7 @@ const { get_app, get_user } = require("../../helpers");
const { UserActorType } = require("../../services/auth/Actor");
const { DB_READ } = require("../../services/database/consts");
const { Context } = require("../../util/context");
const APIError = require('../../api/APIError');
module.exports = eggspress('/auth/list-permissions', {
subdomain: 'api',
@@ -1,6 +1,7 @@
const eggspress = require("../../api/eggspress");
const { UserActorType } = require("../../services/auth/Actor");
const { Context } = require("../../util/context");
const APIError = require('../../api/APIError');
module.exports = eggspress('/auth/list-sessions', {
subdomain: 'api',
@@ -19,6 +19,7 @@
const eggspress = require("../../api/eggspress");
const { UserActorType } = require("../../services/auth/Actor");
const { Context } = require("../../util/context");
const APIError = require('../../api/APIError');
module.exports = eggspress('/auth/revoke-user-app', {
subdomain: 'api',
+21 -58
View File
@@ -28,62 +28,6 @@ const config = require('../config.js');
const jwt = require('jsonwebtoken');
const { invalidate_cached_user_by_id } = require('../helpers.js');
const CHANGE_EMAIL_START = eggspress('/change_email/start', {
subdomain: 'api',
auth: true,
verified: true,
allowedMethods: ['POST'],
}, async (req, res, next) => {
const user = req.user;
const new_email = req.body.new_email;
// TODO: DRY: signup.js
// validation
if( ! new_email ) {
throw APIError.create('field_missing', null, { key: 'new_email' });
}
if ( typeof new_email !== 'string' ) {
throw APIError.create('field_invalid', null, {
key: 'new_email', expected: 'a valid email address' });
}
if ( ! validator.isEmail(new_email) ) {
throw APIError.create('field_invalid', null, {
key: 'new_email', expected: 'a valid email address' });
}
// check if email is already in use
const db = req.services.get('database').get(DB_WRITE, 'auth');
const rows = await db.read(
'SELECT COUNT(*) AS `count` FROM `user` WHERE `email` = ?',
[new_email]
);
if ( rows[0].count > 0 ) {
throw APIError.create('email_already_in_use', null, { email: new_email });
}
// generate confirmation token
const token = crypto.randomBytes(4).toString('hex');
const jwt_token = jwt.sign({
user_id: user.id,
token,
}, config.jwt_secret, { expiresIn: '24h' });
// send confirmation email
const svc_email = req.services.get('email');
await svc_email.send_email({ email: new_email }, 'email_change_request', {
confirm_url: `${config.origin}/change_email/confirm?token=${jwt_token}`,
username: user.username,
});
// update user
await db.write(
'UPDATE `user` SET `unconfirmed_change_email` = ?, `change_email_confirm_token` = ? WHERE `id` = ?',
[new_email, token, user.id]
);
res.send({ success: true });
});
const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', {
allowedMethods: ['GET'],
}, async (req, res, next) => {
@@ -93,6 +37,11 @@ const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', {
throw APIError.create('field_missing', null, { key: 'token' });
}
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('change-email-confirm') ) {
return res.status(429).send('Too many requests.');
}
const { token, user_id } = jwt.verify(jwt_token, config.jwt_secret);
const db = req.services.get('database').get(DB_WRITE, 'auth');
@@ -104,10 +53,25 @@ const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', {
throw APIError.create('token_invalid');
}
// Scenario: email was confirmed on another account already
const rows2 = await db.read(
'SELECT `id` FROM `user` WHERE `email` = ?',
[rows[0].unconfirmed_change_email]
);
if ( rows2.length > 0 ) {
throw APIError.create('email_already_in_use');
}
// If other users have the same unconfirmed email, revoke it
await db.write(
'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?',
[rows[0].unconfirmed_change_email]
);
const new_email = rows[0].unconfirmed_change_email;
await db.write(
'UPDATE `user` SET `email` = ?, `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `id` = ?',
'UPDATE `user` SET `email` = ?, `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL, `pass_recovery_token` = NULL WHERE `id` = ?',
[new_email, user_id]
);
@@ -122,6 +86,5 @@ const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', {
});
module.exports = app => {
app.use(CHANGE_EMAIL_START);
app.use(CHANGE_EMAIL_CONFIRM);
}
@@ -54,6 +54,11 @@ module.exports = eggspress('/change_username', {
if(await username_exists(req.body.new_username))
throw APIError.create('username_already_in_use', null, { username: req.body.new_username });
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('change-email-start') ) {
return res.status(429).send('Too many requests.');
}
const db = Context.get('services').get('database').get(DB_WRITE, 'auth');
// Has the user already changed their username twice this month?
@@ -22,6 +22,7 @@ const { invalidate_cached_user } = require('../helpers');
const router = new express.Router();
const auth = require('../middleware/auth.js');
const { DB_WRITE } = require('../services/database/consts');
const APIError = require('../api/APIError.js');
// -----------------------------------------------------------------------//
// POST /confirm-email
@@ -34,6 +35,11 @@ router.post('/confirm-email', auth, express.json(), async (req, res, next)=>{
if(!req.body.code)
req.status(400).send('code is required');
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('confirm-email') ) {
return res.status(429).send('Too many requests.');
}
// Modules
const db = req.services.get('database').get(DB_WRITE, 'auth');
@@ -43,6 +49,22 @@ router.post('/confirm-email', auth, express.json(), async (req, res, next)=>{
// Set expiry for rate limit
kv.expire(`confirm-email|${req.ip}|${req.body.email ?? req.body.username}`, 60 * 10, 'NX')
// Scenario: email was confirmed on another account already
const rows = await db.read(
'SELECT `id` FROM `user` WHERE `email` = ? AND `email_confirmed` = 1',
[req.body.email],
);
if ( rows.length > 0 ) {
APIError.create('email_already_in_use').write(res);
return;
}
// If other users have the same unconfirmed email, revoke it
await db.write(
'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?',
[req.user.email],
);
if(req.body.code === req.user.email_confirm_code) {
await db.write(
"UPDATE `user` SET `email_confirmed` = 1, `requires_email_confirmation` = 0 WHERE id = ? LIMIT 1",
+7 -18
View File
@@ -32,10 +32,6 @@ router.post('/contactUs', auth, express.json(), async (req, res, next)=>{
if(require('../helpers').subdomain(req) !== 'api')
next();
// check if user is verified
if((config.strict_email_verification_required || req.user.requires_email_confirmation) && !req.user.email_confirmed)
return res.status(400).send({code: 'account_is_not_verified', message: 'Account is not verified'});
// message is required
if(!req.body.message)
return res.status(400).send({message: 'message is required'})
@@ -46,6 +42,11 @@ router.post('/contactUs', auth, express.json(), async (req, res, next)=>{
else if(req.body.message.length > 100000)
return res.status(400).send({message: 'message is too long'})
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('contact-us') ) {
return res.status(429).send('Too many requests.');
}
// modules
const db = req.services.get('database').get(DB_WRITE, 'feedback');
@@ -66,20 +67,8 @@ router.post('/contactUs', auth, express.json(), async (req, res, next)=>{
let user = await get_user({id: req.user.id});
// send email to support
const nodemailer = require("nodemailer");
// send email notif
let transporter = nodemailer.createTransport({
host: config.smtp_server,
port: config.smpt_port,
secure: true, // STARTTLS
auth: {
user: config.smtp_username,
pass: config.smtp_password,
},
});
transporter.sendMail({
const svc_email = req.services.get('email');
svc_email.sendMail({
from: '"Puter" [email protected]', // sender address
to: '[email protected]', // list of receivers
replyTo: user.email === null ? undefined : user.email,
@@ -40,7 +40,6 @@ router.post('/delete-site', auth, express.json(), async (req, res, next)=>{
return res.status(400).send('site_uuid is required')
// modules
const {} = require('../helpers');
const db = req.services.get('database').get(DB_WRITE, 'subdomains:legacy');
await db.write(
+7 -1
View File
@@ -11,7 +11,7 @@ const { HLRead } = require('../filesystem/hl_operations/hl_read.js');
// -----------------------------------------------------------------------//
// GET /down
// -----------------------------------------------------------------------//
router.get('/down', auth, fs, express.json(), async (req, res, next)=>{
router.post('/down', auth, fs, express.json(), async (req, res, next)=>{
// check subdomain
if(require('../helpers').subdomain(req) !== 'api')
next();
@@ -20,6 +20,12 @@ router.get('/down', auth, fs, express.json(), async (req, res, next)=>{
if((config.strict_email_verification_required || req.user.requires_email_confirmation) && !req.user.email_confirmed)
return res.status(400).send({code: 'account_is_not_verified', message: 'Account is not verified'});
// check anti-csrf token
const svc_antiCSRF = req.services.get('anti-csrf');
if ( ! svc_antiCSRF.consume_token(req.user.uuid, req.body.anti_csrf) ) {
return res.status(400).json({ message: 'incorrect anti-CSRF token' });
}
// validation
if(!req.query.path)
return res.status(400).send('path is required')
@@ -143,7 +143,7 @@ module.exports = eggspress('/drivers/usage', {
// usages.apps.push(usage);
}
for ( k in usages.apps ) {
for ( const k in usages.apps ) {
usages.apps[k] = Object.values(usages.apps[k]);
}
+4 -3
View File
@@ -65,8 +65,9 @@ const script = async function script () {
return await response.json();
};
/* global window */
window.addEventListener('message', async event => {
const { id, interface, method, params } = event.data;
const { id, interface: interface_, method, params } = event.data;
let has_file = false;
for ( const k in params ) {
if ( params[k] instanceof File ) {
@@ -75,11 +76,11 @@ const script = async function script () {
}
}
const result = has_file ? await fcall({
interface_name: interface,
interface_name: interface_,
method_name: method,
params,
}) : await call({
interface_name: interface,
interface_name: interface_,
method_name: method,
params,
});
+1 -1
View File
@@ -96,7 +96,7 @@ router.get('/file', async (req, res, next)=>{
res.resource_owner = fsentry[0].user_id;
// try to deduce content-type
const contentType = mime.contentType(fsentry[0].name)
const contentType = "application/octet-stream";
// update `accessed`
db.write(
@@ -26,6 +26,7 @@ const Busboy = require('busboy');
const { BatchExecutor } = require("../../../filesystem/batch/BatchExecutor");
const { TeePromise } = require("../../../util/promise");
const { EWMA, MovingMode } = require("../../../util/opmath");
const { get_app } = require('../../../helpers');
const commands = require('../../../filesystem/batch/commands.js').commands;
@@ -191,7 +192,11 @@ module.exports = eggspress('/batch', {
}
if ( fieldname === 'fileinfo' ) {
fileinfos.push(JSON.parse(value));
const fileinfo = JSON.parse(value);
if ( fileinfo.size < 0 ) {
throw APIError.create('invalid_file_metadata');
}
fileinfos.push(fileinfo);
return;
}
@@ -221,28 +226,6 @@ module.exports = eggspress('/batch', {
let ps = [];
busboy.on('file', async (fieldname, stream, detais) => {
if (false) {
ended[i] = false;
ps[i] = new TeePromise();
const this_i = i;
stream.on('end', () => {
ps[this_i].resolve();
ended[this_i] = true;
batch_widget.ec++;
});
if ( i > 0 ) {
if ( ! ended[i-1] ) {
batch_widget.sc++;
// stream.pause();
batch_widget.wc++;
await Promise.all(Array(i).fill(0).map((_, j) => ps[j]));
batch_widget.wc--;
// stream.resume();
}
}
i++;
}
if ( batch_exe.total_tbd ) {
batch_exe.total_tbd = false;
batch_widget.ic = pending_operations.length;
@@ -66,18 +66,6 @@ module.exports = eggspress('/copy', {
x.set(operationTraceSvc.ckey('frame'), frame);
}
// TEMP: Testing copy with its own sql queue
if ( false ) {
const x = Context.get();
const svc = new ProxyContainer(x.get('services'));
const s = new DatabaseFSEntryService({
services: x.get('services'),
label: 'Copy-DatabaseFSEntryService',
});
svc.set('systemFSEntryService', s);
x.set('services', svc);
}
const log = req.services.get('log-service').create('copy');
const filesystem = req.services.get('filesystem');
@@ -103,7 +91,6 @@ module.exports = eggspress('/copy', {
source: req.values.source,
new_name: req.body.new_name,
new_name: req.body.new_name,
overwrite: req.body.overwrite ?? false,
dedupe_name,
@@ -74,15 +74,4 @@ module.exports = eggspress('/read', {
res.set('Content-Type', 'application/octet-stream');
stream.pipe(res);
return;
const filesystem = req.services.get('filesystem');
await filesystem.read(req.fs, res, {
...req.values,
user: req.user,
version_id: req.query.version_id,
line_count,
byte_count,
});
});
@@ -49,12 +49,10 @@ module.exports = eggspress('/token-read', {
const actor = await svc_auth.authenticate_from_token(access_jwt);
if ( ! actor ) {
throw new Error('A');
throw APIError.create('token_auth_failed');
}
if ( ! (actor.type instanceof AccessTokenActorType) ) {
throw new Error('B');
throw APIError.create('token_auth_failed');
}
@@ -98,16 +96,5 @@ module.exports = eggspress('/token-read', {
res.setHeader('Content-Type', mime_type);
stream.pipe(res);
return;
const filesystem = req.services.get('filesystem');
await filesystem.read(req.fs, res, {
...req.values,
user: req.user,
version_id: req.query.version_id,
line_count,
byte_count,
});
});
@@ -16,16 +16,17 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
class Registry {
constructor() {
this._registry = {};
}
"use strict"
const express = require('express');
const router = new express.Router();
put(name, value) {
this._registry[name] = value;
}
// -----------------------------------------------------------------------//
// GET /healthcheck
// -----------------------------------------------------------------------//
router.get('/healthcheck', async (req, res) => {
const svc_serverHealth = req.services.get('server-health');
get(name) {
return this._registry[name];
}
}
const status = await svc_serverHealth.get_status();
res.json(status);
})
module.exports = router
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const api_error_handler = require("../../api/api_error_handler");
const config = require("../../config");
const { get_user, get_app, id2path } = require("../../helpers");
@@ -62,7 +62,7 @@ class PuterSiteMiddleware extends AdvancedBase {
req.subdomains[0] === 'devtest' ? 'devtest' :
req.hostname.slice(0, -1 * (config.static_hosting_domain.length + 1));
let path = (req.baseUrl + req.path) ?? 'index.html';
let path = (req.baseUrl + req.path) || 'index.html';
const context = Context.get();
const services = context.get('services');
@@ -38,6 +38,8 @@ module.exports = eggspress('/clearItems', {
}
const svc_mysql = req.services.get('mysql');
// TODO: Check if used anywhere, maybe remove
// eslint-disable-next-line no-undef
const dbrw = svc_mysql.get(DB_MODE_WRITE, 'kvstore-clearItems');
await dbrw.execute(
`DELETE FROM kv WHERE user_id=? AND app=?`,
+176 -26
View File
@@ -21,6 +21,36 @@ const express = require('express');
const router = new express.Router();
const { get_user, body_parser_error_handler } = require('../helpers');
const config = require('../config');
const { DB_WRITE } = require('../services/database/consts');
const complete_ = async ({ req, res, user }) => {
const svc_auth = req.services.get('auth');
const { token } = await svc_auth.create_session_token(user, { req });
//set cookie
// res.cookie(config.cookie_name, token);
res.cookie(config.cookie_name, token, {
sameSite: 'none',
secure: true,
httpOnly: true,
});
// send response
console.log('200 response?');
return res.send({
proceed: true,
next_step: 'complete',
token: token,
user:{
username: user.username,
uuid: user.uuid,
email: user.email,
email_confirmed: user.email_confirmed,
is_temp: (user.password === null && user.email === null),
}
})
};
// -----------------------------------------------------------------------//
// POST /file
@@ -32,7 +62,6 @@ router.post('/login', express.json(), body_parser_error_handler, async (req, res
// modules
const bcrypt = require('bcrypt')
const jwt = require('jsonwebtoken')
const validator = require('validator')
// either username or email must be provided
@@ -60,11 +89,10 @@ router.post('/login', express.json(), body_parser_error_handler, async (req, res
else if(req.body.email && !validator.isEmail(req.body.email))
return res.status(400).send('Invalid email.')
// Increment & check rate limit
if(kv.incr(`login|${req.ip}|${req.body.email ?? req.body.username}`) > 10)
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('login') ) {
return res.status(429).send('Too many requests.');
// Set expiry for rate limit
kv.expire(`login|${req.ip}|${req.body.email ?? req.body.username}`, 60*10, 'NX')
}
try{
let user;
@@ -89,34 +117,156 @@ router.post('/login', express.json(), body_parser_error_handler, async (req, res
return res.status(400).send('Incorrect password.')
// check password
if(await bcrypt.compare(req.body.password, user.password)){
const svc_auth = req.services.get('auth');
const { token } = await svc_auth.create_session_token(user, { req });
//set cookie
// res.cookie(config.cookie_name, token);
res.cookie(config.cookie_name, token, {
sameSite: 'none',
secure: true,
httpOnly: true,
});
// We create a JWT that can ONLY be used on the endpoint that
// accepts the OTP code.
if ( user.otp_enabled ) {
const svc_token = req.services.get('token');
const otp_jwt_token = svc_token.sign('otp', {
user_uid: user.uuid,
}, { expiresIn: '5m' });
// send response
return res.send({
token: token,
user:{
username: user.username,
uuid: user.uuid,
email: user.email,
email_confirmed: user.email_confirmed,
is_temp: (user.password === null && user.email === null),
}
})
return res.status(202).send({
proceed: true,
next_step: 'otp',
otp_jwt_token: otp_jwt_token,
});
}
console.log('UMM?');
return await complete_({ req, res, user });
}else{
return res.status(400).send('Incorrect password.')
}
}catch(e){
console.error(e);
return res.status(400).send(e);
}
})
module.exports = router
router.post('/login/otp', express.json(), body_parser_error_handler, async (req, res, next) => {
// either api. subdomain or no subdomain
if(require('../helpers').subdomain(req) !== 'api' && require('../helpers').subdomain(req) !== '')
next();
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('login-otp') ) {
return res.status(429).send('Too many requests.');
}
if ( ! req.body.token ) {
return res.status(400).send('token is required.');
}
if ( ! req.body.code ) {
return res.status(400).send('code is required.');
}
const svc_token = req.services.get('token');
let decoded; try {
decoded = svc_token.verify('otp', req.body.token);
} catch ( e ) {
return res.status(400).send('Invalid token.');
}
if ( ! decoded.user_uid ) {
return res.status(400).send('Invalid token.');
}
const user = await get_user({ uuid: decoded.user_uid, cached: false });
if ( ! user ) {
return res.status(400).send('User not found.');
}
const svc_otp = req.services.get('otp');
if ( ! svc_otp.verify(user.username, user.otp_secret, req.body.code) ) {
// THIS MAY BE COUNTER-INTUITIVE
//
// A successfully handled request, with the correct format,
// but incorrect credentials when NOT using the HTTP
// authentication framework provided by RFC 7235, SHOULD
// return status 200.
//
// Source: I asked Julian Reschke in an email, and then he
// contributed to this discussion:
// https://stackoverflow.com/questions/32752578
return res.status(200).send({
proceed: false,
});
}
return await complete_({ req, res, user });
});
router.post('/login/recovery-code', express.json(), body_parser_error_handler, async (req, res, next) => {
// either api. subdomain or no subdomain
if(require('../helpers').subdomain(req) !== 'api' && require('../helpers').subdomain(req) !== '')
next();
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('login-recovery') ) {
return res.status(429).send('Too many requests.');
}
if ( ! req.body.token ) {
return res.status(400).send('token is required.');
}
if ( ! req.body.code ) {
return res.status(400).send('code is required.');
}
const svc_token = req.services.get('token');
let decoded; try {
decoded = svc_token.verify('otp', req.body.token);
} catch ( e ) {
return res.status(400).send('Invalid token.');
}
if ( ! decoded.user_uid ) {
return res.status(400).send('Invalid token.');
}
const user = await get_user({ uuid: decoded.user_uid, cached: false });
if ( ! user ) {
return res.status(400).send('User not found.');
}
const code = req.body.code;
const crypto = require('crypto');
const codes = user.otp_recovery_codes.split(',');
const hashed_code = crypto
.createHash('sha256')
.update(code)
.digest('base64')
// We're truncating the hash for easier storage, so we have 128
// bits of entropy instead of 256. This is plenty for recovery
// codes, which have only 48 bits of entropy to begin with.
.slice(0, 22);
if ( ! codes.includes(hashed_code) ) {
return res.status(200).send({
proceed: false,
});
}
// Remove the code from the list
const index = codes.indexOf(hashed_code);
codes.splice(index, 1);
// update user
const db = req.services.get('database').get(DB_WRITE, '2fa');
await db.write(
`UPDATE user SET otp_recovery_codes = ? WHERE uuid = ?`,
[codes.join(','), user.uuid]
);
user.otp_recovery_codes = codes.join(',');
return await complete_({ req, res, user });
});
module.exports = router;
+5
View File
@@ -29,6 +29,11 @@ router.post('/logout', auth, express.json(), async (req, res, next)=>{
// check subdomain
if(require('../helpers').subdomain(req) !== 'api' && require('../helpers').subdomain(req) !== '')
next();
// check anti-csrf token
const svc_antiCSRF = req.services.get('anti-csrf');
if ( ! svc_antiCSRF.consume_token(req.user.uuid, req.body.anti_csrf) ) {
return res.status(400).json({ message: 'incorrect anti-CSRF token' });
}
// delete cookie
res.clearCookie(config.cookie_name);
// delete session
+1 -1
View File
@@ -45,7 +45,7 @@ module.exports = eggspress('/open_item', {
const subject = req.values.subject;
const actor = Context.get('actor');
if ( ! actor.type instanceof UserActorType ) {
if ( ! (actor.type instanceof UserActorType) ) {
throw APIError.create('forbidden');
}
+13 -3
View File
@@ -18,7 +18,7 @@
*/
"use strict"
const express = require('express');
const { invalidate_cached_user } = require('../helpers');
const { invalidate_cached_user, get_user } = require('../helpers');
const router = new express.Router();
const auth = require('../middleware/auth.js');
const { DB_WRITE } = require('../services/database/consts');
@@ -45,9 +45,15 @@ router.post('/passwd', auth, express.json(), async (req, res, next)=>{
else if (typeof req.body.new_pass !== 'string')
return res.status(400).send('new_pass must be a string.')
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('passwd') ) {
return res.status(429).send('Too many requests.');
}
try{
const user = await get_user({ id: req.user.id, force: true });
// check old_pass
const isMatch = await bcrypt.compare(req.body.old_pass, req.user.password)
const isMatch = await bcrypt.compare(req.body.old_pass, user.password)
if(!isMatch)
return res.status(400).send('old_pass does not match your current password.')
// check new_pass length
@@ -56,10 +62,14 @@ router.post('/passwd', auth, express.json(), async (req, res, next)=>{
return res.status(400).send('new_pass must be at least 6 characters long.')
else{
await db.write(
'UPDATE user SET password=? WHERE `id` = ?',
'UPDATE user SET password=?, `pass_recovery_token` = NULL, `change_email_confirm_token` = NULL WHERE `id` = ?',
[await bcrypt.hash(req.body.new_pass, 8), req.user.id]
);
invalidate_cached_user(req.user);
const svc_email = req.services.get('email');
svc_email.send_email({ email: user.email }, 'password_change_notification');
return res.send('Password successfully updated.')
}
}catch(e){
+122 -112
View File
@@ -19,7 +19,7 @@
"use strict"
const express = require('express');
const router = new express.Router();
const {get_taskbar_items, username_exists, send_email_verification_code, send_email_verification_token, invalidate_cached_user} = require('../helpers');
const {get_taskbar_items, username_exists, send_email_verification_code, send_email_verification_token, invalidate_cached_user, get_user } = require('../helpers');
const auth = require('../middleware/auth.js');
const config = require('../config');
const { Context } = require('../util/context');
@@ -70,127 +70,137 @@ router.post('/save_account', auth, express.json(), async (req, res, next)=>{
else if(req.body.password.length < config.min_pass_length)
return res.status(400).send(`Password must be at least ${config.min_pass_length} characters long.`)
// duplicate username check, do this only if user has supplied a new username
if(req.body.username !== req.user.username && await username_exists(req.body.username))
return res.status(400).send('This username already exists in our database. Please use another one.');
// duplicate email check (pseudo-users don't count)
let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]);
if(rows2[0].email_exists)
return res.status(400).send('This email already exists in our database. Please use another one.');
// get pseudo user, if exists
let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]);
pseudo_user = pseudo_user[0];
// get uuid user, if exists
if(req.body.uuid){
uuid_user = await db.read(`SELECT * FROM user WHERE uuid = ? LIMIT 1`, [req.body.uuid]);
uuid_user = uuid_user[0];
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('save-account') ) {
return res.status(429).send('Too many requests.');
}
// send_confirmation_code
req.body.send_confirmation_code = req.body.send_confirmation_code ?? true;
const svc_lock = req.services.get('lock');
return svc_lock.lock([
`save-account:username:${req.body.username}`,
`save-account:email:${req.body.email}`
], async () => {
await new Promise((rslv) => {
setTimeout(rslv, 5000);
});
// duplicate username check, do this only if user has supplied a new username
if(req.body.username !== req.user.username && await username_exists(req.body.username))
return res.status(400).send('This username already exists in our database. Please use another one.');
// duplicate email check (pseudo-users don't count)
let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]);
if(rows2[0].email_exists)
return res.status(400).send('This email already exists in our database. Please use another one.');
// get pseudo user, if exists
let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]);
pseudo_user = pseudo_user[0];
// todo email confirmation is required by default unless:
// Pseudo user converting and matching uuid is provided
let email_confirmation_required = 0;
// send_confirmation_code
req.body.send_confirmation_code = req.body.send_confirmation_code ?? true;
// -----------------------------------
// Get referral user
// -----------------------------------
let referred_by_user = undefined;
if ( req.body.referral_code ) {
referred_by_user = await get_user({ referral_code: req.body.referral_code });
if ( ! referred_by_user ) {
return res.status(400).send('Referral code not found');
// todo email confirmation is required by default unless:
// Pseudo user converting and matching uuid is provided
let email_confirmation_required = 0;
// -----------------------------------
// Get referral user
// -----------------------------------
let referred_by_user = undefined;
if ( req.body.referral_code ) {
referred_by_user = await get_user({ referral_code: req.body.referral_code });
if ( ! referred_by_user ) {
return res.status(400).send('Referral code not found');
}
}
}
// -----------------------------------
// New User
// -----------------------------------
const user_uuid = req.user.uuid;
let email_confirm_code = Math.floor(100000 + Math.random() * 900000);
const email_confirm_token = uuidv4();
// -----------------------------------
// New User
// -----------------------------------
const user_uuid = req.user.uuid;
let email_confirm_code = Math.floor(100000 + Math.random() * 900000);
const email_confirm_token = uuidv4();
if(pseudo_user === undefined){
await db.write(
`UPDATE user
SET
username = ?, email = ?, password = ?, email_confirm_code = ?, email_confirm_token = ?${
referred_by_user ? ', referred_by = ?' : '' }
WHERE
id = ?`,
[
// username
req.body.username,
// email
req.body.email,
// password
await bcrypt.hash(req.body.password, 8),
// email_confirm_code
email_confirm_code,
//email_confirm_token
email_confirm_token,
// referred_by
...(referred_by_user ? [referred_by_user.id] : []),
// id
req.user.id
]
);
invalidate_cached_user(req.user);
if(pseudo_user === undefined){
await db.write(
`UPDATE user
SET
username = ?, email = ?, password = ?, email_confirm_code = ?, email_confirm_token = ?${
referred_by_user ? ', referred_by = ?' : '' }
WHERE
id = ?`,
[
// username
req.body.username,
// email
req.body.email,
// password
await bcrypt.hash(req.body.password, 8),
// email_confirm_code
email_confirm_code,
//email_confirm_token
email_confirm_token,
// referred_by
...(referred_by_user ? [referred_by_user.id] : []),
// id
req.user.id
]
);
invalidate_cached_user(req.user);
// Update root directory name
await db.write(
`UPDATE fsentries SET name = ? WHERE user_id = ? and parent_uid IS NULL`,
[
// name
req.body.username,
// id
req.user.id,
]
);
const filesystem = req.services.get('filesystem');
await filesystem.update_child_paths(`/${req.user.username}`, `/${req.body.username}`, req.user.id);
// Update root directory name
await db.write(
`UPDATE fsentries SET name = ? WHERE user_id = ? and parent_uid IS NULL`,
[
// name
req.body.username,
// id
req.user.id,
]
);
const filesystem = req.services.get('filesystem');
await filesystem.update_child_paths(`/${req.user.username}`, `/${req.body.username}`, req.user.id);
if(req.body.send_confirmation_code)
send_email_verification_code(email_confirm_code, req.body.email);
else
send_email_verification_token(email_confirm_token, req.body.email, user_uuid);
}
// create token for login
const token = await jwt.sign({uuid: user_uuid}, config.jwt_secret);
// user id
// todo if pseudo user, assign directly no need to do another DB lookup
const user_id = req.user.id;
const user_res = await db.read('SELECT * FROM `user` WHERE `id` = ? LIMIT 1', [user_id]);
const user = user_res[0];
// todo send LINK-based verification email
//set cookie
res.cookie(config.cookie_name, token);
{
const svc_event = req.services.get('event');
svc_event.emit('user.save_account', { user });
}
// return results
return res.send({
token: token,
user:{
username: user.username,
uuid: user.uuid,
email: user.email,
is_temp: false,
requires_email_confirmation: user.requires_email_confirmation,
email_confirmed: user.email_confirmed,
email_confirmation_required: email_confirmation_required,
taskbar_items: await get_taskbar_items(user),
referral_code: user.referral_code,
if(req.body.send_confirmation_code)
send_email_verification_code(email_confirm_code, req.body.email);
else
send_email_verification_token(email_confirm_token, req.body.email, user_uuid);
}
})
// create token for login
const svc_auth = req.services.get('auth');
const { token } = await svc_auth.create_session_token(req.user, { req });
// user id
// todo if pseudo user, assign directly no need to do another DB lookup
const user_id = req.user.id;
const user_res = await db.read('SELECT * FROM `user` WHERE `id` = ? LIMIT 1', [user_id]);
const user = user_res[0];
// todo send LINK-based verification email
//set cookie
res.cookie(config.cookie_name, token);
{
const svc_event = req.services.get('event');
svc_event.emit('user.save_account', { user });
}
// return results
return res.send({
token: token,
user:{
username: user.username,
uuid: user.uuid,
email: user.email,
is_temp: false,
requires_email_confirmation: user.requires_email_confirmation,
email_confirmed: user.email_confirmed,
email_confirmation_required: email_confirmation_required,
taskbar_items: await get_taskbar_items(user),
referral_code: user.referral_code,
}
})
});
})
module.exports = router
@@ -27,6 +27,11 @@ const { DB_WRITE } = require('../services/database/consts.js');
// POST /send-confirm-email
// -----------------------------------------------------------------------//
router.post('/send-confirm-email', auth, express.json(), async (req, res, next)=>{
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('send-confirm-email') ) {
return res.status(429).send('Too many requests.');
}
// check subdomain
if(require('../helpers').subdomain(req) !== 'api')
next();
@@ -23,6 +23,8 @@ const { body_parser_error_handler, get_user, invalidate_cached_user } = require(
const config = require('../config');
const { DB_WRITE } = require('../services/database/consts');
const jwt = require('jsonwebtoken');
// -----------------------------------------------------------------------//
// POST /send-pass-recovery-email
// -----------------------------------------------------------------------//
@@ -51,6 +53,12 @@ router.post('/send-pass-recovery-email', express.json(), body_parser_error_handl
else if(req.body.email && !validator.isEmail(req.body.email))
return res.status(400).send('Invalid email.')
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('send-pass-recovery-email') ) {
return res.status(429).send('Too many requests.');
}
try{
let user;
// see if username exists
@@ -80,31 +88,20 @@ router.post('/send-pass-recovery-email', express.json(), body_parser_error_handl
);
invalidate_cached_user(user);
// prepare email
let transporter = nodemailer.createTransport({
host: config.smtp_server,
port: config.smpt_port,
secure: true, // STARTTLS
auth: {
user: config.smtp_username,
pass: config.smtp_password,
},
});
// create jwt
const jwt_token = jwt.sign({
user_uid: user.uuid,
token,
// email change invalidates password recovery
email: user.email,
}, config.jwt_secret, { expiresIn: '1h' });
// create link
const rec_link = config.origin + '/action/set-new-password?user=' + user.uuid + '&token=' + token;
const rec_link = config.origin + '/action/set-new-password?token=' + jwt_token;
// send email
transporter.sendMail({
from: '[email protected]', // sender address
to: user.email, // list of receivers
subject: "Password Recovery", // Subject line
html: `
<p>Hi there,</p>
<p>A password recovery request was issued for your account, please follow the link below to reset your password:</p>
<p><a href="${rec_link}">${rec_link}</a></p>
<p>Sincerely,</p>
<p>Puter</p>`,
const svc_email = req.services.get('email');
await svc_email.send_email({ email: user.email }, 'email_password_recovery', {
link: rec_link,
});
// Send response
@@ -20,9 +20,14 @@
const express = require('express')
const router = new express.Router()
const config = require('../config')
const { invalidate_cached_user_by_id } = require('../helpers')
const { invalidate_cached_user_by_id, get_user } = require('../helpers')
const { DB_WRITE } = require('../services/database/consts')
const jwt = require('jsonwebtoken');
// Ensure we don't expose branches with differing messages.
const SAFE_NEGATIVE_RESPONSE = 'This password recovery token is no longer valid.';
// -----------------------------------------------------------------------//
// POST /set-pass-using-token
// -----------------------------------------------------------------------//
@@ -39,9 +44,6 @@ router.post('/set-pass-using-token', express.json(), async (req, res, next)=>{
// password is required
if(!req.body.password)
return res.status(401).send('password is required')
// user_id is required
else if(!req.body.user_id)
return res.status(401).send('user_id is required')
// token is required
else if(!req.body.token)
return res.status(401).send('token is required')
@@ -52,14 +54,26 @@ router.post('/set-pass-using-token', express.json(), async (req, res, next)=>{
else if(req.body.password.length < config.min_pass_length)
return res.status(400).send(`Password must be at least ${config.min_pass_length} characters long.`)
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('set-pass-using-token') ) {
return res.status(429).send('Too many requests.');
}
const { token, user_uid, email } = jwt.verify(req.body.token, config.jwt_secret);
const user = await get_user({ uuid: user_uid, force: true });
if ( user.email !== email ) {
return res.status(400).send(SAFE_NEGATIVE_RESPONSE);
}
try{
const info = await db.write(
'UPDATE user SET password=?, pass_recovery_token=NULL WHERE `uuid` = ? AND pass_recovery_token = ?',
[await bcrypt.hash(req.body.password, 8), req.body.user_id, req.body.token]
'UPDATE user SET password=?, pass_recovery_token=NULL, change_email_confirm_token=NULL WHERE `uuid` = ? AND pass_recovery_token = ?',
[await bcrypt.hash(req.body.password, 8), user_uid, token],
);
if ( ! info?.anyRowsAffected ) {
return res.status(400).send('Invalid token or user_id.');
return res.status(400).send(SAFE_NEGATIVE_RESPONSE);
}
invalidate_cached_user_by_id(req.body.user_id);
+4 -3
View File
@@ -34,7 +34,7 @@ module.exports = eggspress('/sign', {
allowedMethods: ['POST'],
}, async (req, res, next)=>{
const actor = Context.get('actor');
if ( ! actor.type instanceof UserActorType ) {
if ( ! (actor.type instanceof UserActorType) ) {
throw APIError.create('forbidden');
}
@@ -62,7 +62,8 @@ module.exports = eggspress('/sign', {
app = await get_app({ uid: req.body.app_uid });
if ( ! app ) {
throw APIError.create('no_suitable_app', null, { entry_name: subject.entry.name });
// FIXME: subject.entry.name isn't available here
throw APIError.create('no_suitable_app', null); //, { entry_name: subject.entry.name });
}
// Generate user-app token
const svc_auth = Context.get('services').get('auth');
@@ -111,7 +112,7 @@ module.exports = eggspress('/sign', {
const svc_acl = Context.get('services').get('acl');
if ( ! await svc_acl.check(actor, node, 'see') ) {
throw await svc_acl.get_safe_acl_error(actor, subject, 'see');
throw await svc_acl.get_safe_acl_error(actor, node, 'see');
}
if ( app !== null ) {
+6 -1
View File
@@ -44,6 +44,11 @@ module.exports = eggspress(['/signup'], {
if(require('../helpers').subdomain(req) !== 'api' && require('../helpers').subdomain(req) !== '')
next();
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('signup') ) {
return res.status(429).send('Too many requests.');
}
// modules
const db = req.services.get('database').get(DB_WRITE, 'auth');
const bcrypt = require('bcrypt')
@@ -246,7 +251,7 @@ module.exports = eggspress(['/signup'], {
// todo if pseudo user, assign directly no need to do another DB lookup
const user_id = (pseudo_user === undefined) ? insert_res.insertId : pseudo_user.id;
const [user] = await db.read(
const [user] = await db.pread(
'SELECT * FROM `user` WHERE `id` = ? LIMIT 1',
[user_id]
);
@@ -0,0 +1,68 @@
const APIError = require("../../api/APIError");
const { DB_WRITE } = require("../../services/database/consts");
const jwt = require('jsonwebtoken');
const validator = require('validator');
const crypto = require('crypto');
const config = require("../../config");
module.exports = {
route: '/change-email',
methods: ['POST'],
handler: async (req, res, next) => {
const user = req.user;
const new_email = req.body.new_email;
console.log('DID REACH HERE');
// TODO: DRY: signup.js
// validation
if( ! new_email ) {
throw APIError.create('field_missing', null, { key: 'new_email' });
}
if ( typeof new_email !== 'string' ) {
throw APIError.create('field_invalid', null, {
key: 'new_email', expected: 'a valid email address' });
}
if ( ! validator.isEmail(new_email) ) {
throw APIError.create('field_invalid', null, {
key: 'new_email', expected: 'a valid email address' });
}
// check if email is already in use
const db = req.services.get('database').get(DB_WRITE, 'auth');
const rows = await db.read(
'SELECT COUNT(*) AS `count` FROM `user` WHERE `email` = ?',
[new_email]
);
if ( rows[0].count > 0 ) {
throw APIError.create('email_already_in_use', null, { email: new_email });
}
// generate confirmation token
const token = crypto.randomBytes(4).toString('hex');
const jwt_token = jwt.sign({
user_id: user.id,
token,
}, config.jwt_secret, { expiresIn: '24h' });
// send confirmation email
const svc_email = req.services.get('email');
await svc_email.send_email({ email: new_email }, 'email_change_request', {
confirm_url: `${config.origin}/change_email/confirm?token=${jwt_token}`,
username: user.username,
});
const old_email = user.email;
// TODO: NotificationService
await svc_email.send_email({ email: old_email }, 'email_change_notification', {
new_email: new_email,
});
// update user
await db.write(
'UPDATE `user` SET `unconfirmed_change_email` = ?, `change_email_confirm_token` = ? WHERE `id` = ?',
[new_email, token, user.id]
);
res.send({ success: true });
}
};
@@ -0,0 +1,93 @@
// TODO: DRY: This is the same function used by UIWindowChangePassword!
const { invalidate_cached_user } = require("../../helpers");
const { DB_WRITE } = require("../../services/database/consts");
// duplicate definition is in src/helpers.js (puter GUI)
const check_password_strength = (password) => {
// Define criteria for password strength
const criteria = {
minLength: 8,
hasUpperCase: /[A-Z]/.test(password),
hasLowerCase: /[a-z]/.test(password),
hasNumber: /\d/.test(password),
hasSpecialChar: /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)
};
let overallPass = true;
// Initialize report object
let criteria_report = {
minLength: {
message: `Password must be at least ${criteria.minLength} characters long`,
pass: password.length >= criteria.minLength,
},
hasUpperCase: {
message: 'Password must contain at least one uppercase letter',
pass: criteria.hasUpperCase,
},
hasLowerCase: {
message: 'Password must contain at least one lowercase letter',
pass: criteria.hasLowerCase,
},
hasNumber: {
message: 'Password must contain at least one number',
pass: criteria.hasNumber,
},
hasSpecialChar: {
message: 'Password must contain at least one special character',
pass: criteria.hasSpecialChar,
},
};
// Check overall pass status and add messages
for (let criterion in criteria) {
if (!criteria_report[criterion].pass) {
overallPass = false;
break;
}
}
return {
overallPass: overallPass,
report: criteria_report,
};
}
module.exports = {
route: '/change-password',
methods: ['POST'],
handler: async (req, res, next) => {
// Validate new password
const { new_pass } = req.body;
const { overallPass: strong } = check_password_strength(new_pass);
if ( ! strong ) {
req.status(400).send('Password does not meet requirements.');
}
// Update user
// TODO: DI for endpoint definitions like this one
const bcrypt = require('bcrypt');
const db = req.services.get('database').get(DB_WRITE, 'auth');
await db.write(
'UPDATE user SET password=?, `pass_recovery_token` = NULL, `change_email_confirm_token` = NULL WHERE `id` = ?',
[await bcrypt.hash(req.body.new_pass, 8), req.user.id]
);
invalidate_cached_user(req.user);
// Notify user about password change
// TODO: audit log for user in security tab
const svc_email = req.services.get('email');
svc_email.send_email({ email: req.user.email }, 'password_change_notification');
// Kick out all other sessions
const svc_auth = req.services.get('auth');
const sessions = await svc_auth.list_sessions(req.actor);
for ( const session of sessions ) {
if ( session.current ) continue;
await svc_auth.revoke_session(req.actor, session.uuid);
}
return res.send('Password successfully updated.')
}
};
@@ -0,0 +1,22 @@
const { DB_WRITE } = require("../../services/database/consts");
module.exports = {
route: '/disable-2fa',
methods: ['POST'],
handler: async (req, res, next) => {
const db = req.services.get('database').get(DB_WRITE, '2fa.disable');
await db.write(
`UPDATE user SET otp_enabled = 0, otp_recovery_codes = NULL, otp_secret = NULL WHERE uuid = ?`,
[req.user.uuid]
);
// update cached user
req.user.otp_enabled = 0;
const svc_email = req.services.get('email');
await svc_email.send_email({ email: req.user.email }, 'disabled_2fa', {
username: req.user.username,
});
res.send({ success: true });
}
};
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2024 Puter Technologies Inc.
*
* This file is part of Puter.
*
* Puter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
"use strict"
const express = require('express')
const router = new express.Router()
const config = require('../config')
const { invalidate_cached_user_by_id, get_user } = require('../helpers')
const { DB_WRITE } = require('../services/database/consts')
const jwt = require('jsonwebtoken');
// Ensure we don't expose branches with differing messages.
const SAFE_NEGATIVE_RESPONSE = 'This password recovery token is no longer valid.';
// -----------------------------------------------------------------------//
// POST /verify-pass-recovery-token
// -----------------------------------------------------------------------//
router.post('/verify-pass-recovery-token', express.json(), async (req, res, next)=>{
// check subdomain
if(require('../helpers').subdomain(req) !== 'api' && require('../helpers').subdomain(req) !== '')
next();
if ( ! req.body.token ) {
return res.status(401).send('token is required')
}
const svc_edgeRateLimit = req.services.get('edge-rate-limit');
if ( ! svc_edgeRateLimit.check('verify-pass-recovery-token') ) {
return res.status(429).send('Too many requests.');
}
const { exp, user_uid, email } = jwt.verify(req.body.token, config.jwt_secret);
const user = await get_user({ uuid: user_uid, force: true });
if ( user.email !== email ) {
return res.status(400).send(SAFE_NEGATIVE_RESPONSE);
}
const current_time = Math.floor(Date.now() / 1000);
const time_remaining = exp - current_time;
return res.status(200).send({ time_remaining });
})
module.exports = router
+5
View File
@@ -41,6 +41,8 @@ const WHOAMI_GET = eggspress('/whoami', {
const is_user = actor.type instanceof UserActorType;
console.log('user?', req.user);
// send user object
const details = {
username: req.user.username,
@@ -54,6 +56,7 @@ const WHOAMI_GET = eggspress('/whoami', {
is_temp: (req.user.password === null && req.user.email === null),
taskbar_items: await get_taskbar_items(req.user),
referral_code: req.user.referral_code,
otp: !! req.user.otp_enabled,
...(req.new_token ? { token: req.token } : {})
};
@@ -98,6 +101,8 @@ WHOAMI_POST.post('/whoami', auth, fs, express.json(), async (req, response, next
if(req.query.return_desktop_items === 1 || req.query.return_desktop_items === '1' || req.query.return_desktop_items === 'true'){
// by cached desktop id
if(req.user.desktop_id){
// TODO: Check if used anywhere, maybe remove
// eslint-disable-next-line no-undef
desktop_items = await db.read(
`SELECT * FROM fsentries
WHERE user_id = ? AND parent_uid = ?`,
+2 -2
View File
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("puter-js-common");
const { AdvancedBase } = require("@heyputer/puter-js-common");
const NOOP = async () => {};
@@ -51,7 +51,7 @@ class BaseService extends AdvancedBase {
async __on (id, args) {
const handler = this.__get_event_handler(id);
return await handler(id, args);
return await handler(id, ...args);
}
__get_event_handler (id) {
@@ -27,7 +27,7 @@ class ComplainAboutVersionsService extends BaseService {
if ( ! current_version_data ) {
this.log.warn(
`failed to check ${current_version} in the EOL database`
`failed to check ${major} in the EOL database`
);
return;
}
+21 -1
View File
@@ -26,12 +26,32 @@ class Container {
this.instances_ = {};
this.ready = new TeePromise();
}
/**
* registerService registers a service with the servuces container.
*
* @param {String} name - the name of the service
* @param {BaseService.constructor} cls - an implementation of BaseService
* @param {Array} args - arguments to pass to the service constructor
*/
registerService (name, cls, args) {
const my_config = config.services?.[name] || {};
this.instances_[name] = cls.getInstance
? cls.getInstance({ services: this, config, my_config, name, args })
: new cls({ services: this, config, my_config, name, args }) ;
}
/**
* patchService allows overriding methods on a service that is already
* constructed and initialized.
*
* @param {String} name - the name of the service to patch
* @param {ServicePatch.constructor} patch - the patch
* @param {Array} args - arguments to pass to the patch
*/
patchService (name, patch, args) {
const original_service = this.instances_[name];
const patch_instance = new patch();
patch_instance.patch({ original_service, args });
}
set (name, instance) { this.instances_[name] = instance; }
get (name, opts) {
if ( this.instances_[name] ) {
@@ -93,7 +113,7 @@ class Container {
const promises = [];
for ( const k in this.instances_ ) {
if ( this.instances_[k].__on ) {
promises.push(this.instances_[k].__on(id, ...args));
promises.push(this.instances_[k].__on(id, args));
}
}
await Promise.all(promises);
Loaded 100 of 310 files, more files were not shown because too many files have changed in this diff. Show more