diff --git a/.github/workflows/startos-iso.yaml b/.github/workflows/startos-iso.yaml index d3aa020d8..60b642e19 100644 --- a/.github/workflows/startos-iso.yaml +++ b/.github/workflows/startos-iso.yaml @@ -171,7 +171,7 @@ jobs: - name: Prevent rebuild of compiled artifacts run: | - mkdir -p frontend/dist/raw + mkdir -p web/dist/raw PLATFORM=${{ matrix.platform }} make -t compiled-${{ env.ARCH }}.tar - name: Run iso build diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 000000000..c6082ac25 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,31 @@ +name: Automated Tests + +on: + push: + branches: + - master + - next/* + pull_request: + branches: + - master + - next/* + +env: + NODEJS_VERSION: "18.15.0" + ENVIRONMENT: dev-unstable + +jobs: + test: + name: Run Automated Tests + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - uses: actions/setup-node@v3 + with: + node-version: ${{ env.NODEJS_VERSION }} + + - name: Build And Run Tests + run: make test diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 96a51e3ab..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,429 +0,0 @@ -# v0.3.3 -## Highlights - - x86_64 architecture compatibility - - Kiosk mode - use your Embassy with monitor, keyboard, and mouse (available on x86 builds only, disabled on Raspberry Pi) - - "Updates" tab - view all service updates from all registries in one place - - Various UI/UX improvements - - Various bugfixes and optimizations - -## What's Changed - - Minor typo fixes by @kn0wmad in #1887 - - Update build pipeline by @moerketh in #1896 - - Feature/setup migrate by @elvece in #1841 - - Feat/patch migration by @Blu-J in #1890 - - make js cancellable by @dr-bonez in #1901 - - wip: Making Injectable exec by @Blu-J in #1897 - - Fix/debug by @Blu-J in #1909 - - chore: Fix on the rsync not having stdout. by @Blu-J in #1911 - - install wizard project by @MattDHill in #1893 - - chore: Remove the duplicate loggging information that is making usele… by @Blu-J in #1912 - - Http proxy by @redragonx in #1772 - - fix(marketplace): loosen type in categories component by @waterplea in #1918 - - set custom meta title by @MattDHill in #1915 - - Feature/git hash by @dr-bonez in #1919 - - closes #1900 by @dr-bonez in #1920 - - feature/marketplace icons by @dr-bonez in #1921 - - Bugfix/0.3.3 migration by @dr-bonez in #1922 - - feat: Exposing the rsync that we have to the js by @Blu-J in #1907 - - Feature/install wizard disk info by @dr-bonez in #1923 - - bump shared and marketplace npm versions by @dr-bonez in #1924 - - fix error handling when store unreachable by @dr-bonez in #1925 - - wait for network online before launching init by @dr-bonez in #1930 - - silence service crash notifications by @dr-bonez in #1929 - - disable efi by @dr-bonez in #1931 - - Tor daemon fix by @redragonx in #1934 - - wait for url to be available before launching kiosk by @dr-bonez in #1933 - - fix migration to support portable fatties by @dr-bonez in #1935 - - Add guid to partition type by @MattDHill in #1932 - - add localhost support to the http server by @redragonx in #1939 - - refactor setup wizard by @dr-bonez in #1937 - - feat(shared): Ticker add new component and use it in marketplace by @waterplea in #1940 - - feat: For ota update using rsyncd by @Blu-J in #1938 - - Feat/update progress by @MattDHill in #1944 - - Fix/app show hidden by @MattDHill in #1948 - - create dpkg and iso workflows by @dr-bonez in #1941 - - changing ip addr type by @redragonx in #1950 - - Create mountpoints first by @k0gen in #1949 - - Hard code registry icons by @MattDHill in #1951 - - fix: Cleanup by sending a command and kill when dropped by @Blu-J in #1945 - - Update setup wizard styling by @elvece in #1954 - - Feature/homepage by @elvece in #1956 - - Fix millis by @Blu-J in #1960 - - fix accessing dev tools by @MattDHill in #1966 - - Update/misc UI fixes by @elvece in #1961 - - Embassy-init typo by @redragonx in #1959 - - feature: 0.3.2 -> 0.3.3 upgrade by @dr-bonez in #1958 - - Fix/migrate by @Blu-J in #1962 - - chore: Make validation reject containers by @Blu-J in #1970 - - get pubkey and encrypt password on login by @elvece in #1965 - - Multiple bugs and styling by @MattDHill in #1975 - - filter out usb stick during install by @dr-bonez in #1974 - - fix http upgrades by @dr-bonez in #1980 - - restore interfaces before creating manager by @dr-bonez in #1982 - - fuckit: no patch db locks by @dr-bonez in #1969 - - fix websocket hangup error by @dr-bonez in #1981 - - revert app show to use header and fix back button by @MattDHill in #1984 - - Update/marketplace info by @elvece in #1983 - - force docker image removal by @dr-bonez in #1985 - - do not error if cannot determine live usb device by @dr-bonez in #1986 - - remove community registry from FE defaults by @MattDHill in #1988 - - check environment by @dr-bonez in #1990 - - fix marketplace search and better category disabling by @MattDHill in #1991 - - better migration progress bar by @dr-bonez in #1993 - - bump cargo version by @dr-bonez in #1995 - - preload icons and pause on setup complete for kiosk mode by @MattDHill in #1997 - - use squashfs for rpi updates by @dr-bonez in #1998 - - do not start progress at 0 before diff complete by @dr-bonez in #1999 - - user must click continue in kiosk on success page by @MattDHill in #2001 - - fix regex in image rip script by @dr-bonez in #2002 - - fix bug with showing embassy drives and center error text by @MattDHill in #2006 - - fix partition type by @dr-bonez in #2007 - - lowercase service for alphabetic sorting by @MattDHill in #2008 - - dont add updates cat by @MattDHill in #2009 - - make downloaded page a full html doc by @MattDHill in #2011 - - wait for monitor to be attached before launching firefox by @chrisguida in #2005 - - UI fixes by @elvece in #2014 - - fix: Stop service before by @Blu-J in #2019 - - shield links update by @k0gen in #2018 - - fix: Undoing the breaking introduced by trying to stopp by @Blu-J in #2023 - - update link rename from embassy -> system by @elvece in #2027 - - initialize embassy before restoring packages by @dr-bonez in #2029 - - make procfs an optional dependency so sdk can build on macos by @elvece in #2028 - - take(1) for recover select by @MattDHill in #2030 - - take one from server info to prevent multiple reqs to registries by @MattDHill in #2032 - - remove write lock during backup by @MattDHill in #2033 - - fix: Ensure that during migration we make the urls have a trailing slash by @Blu-J in #2036 - - fix: Make the restores limited # restore at a time by @Blu-J in #2037 - - fix error and display of unknown font weight on success page by @elvece in #2038 - -## Checksums -``` -8602e759d3ece7cf503b9ca43e8419109f14e424617c2703b3771c8801483d7e embassyos_amd64.deb -b5c0d8d1af760881a1b5cf32bd7c5b1d1cf6468f6da594a1b4895a866d03a58c embassyos_amd64.iso -fe518453a7e1a8d8c2be43223a1a12adff054468f8082df0560e1ec50df3dbfd embassyos_raspberrypi.img -7b1ff0ada27b6714062aa991ec31c2d95ac4edf254cd464a4fa251905aa47ebd embassyos_raspberrypi.tar.gz -``` - -# v0.3.2.1 -## What's Changed - - Update index.html copy and styling by @elvece in #1855 - - increase maximum avahi entry group size by @dr-bonez in #1869 - - bump version by @dr-bonez in #1871 - -### Linux and Mac - -Download the `eos.tar.gz` file, then extract and flash the resulting eos.img to your SD Card -Windows - -Download the `eos.zip` file, then extract and flash the resulting eos.img to your SD Card - -## SHA-256 Checksums -``` -c4b17658910dd10c37df134d5d5fdd6478f962ba1b803d24477d563d44430f96 eos.tar.gz -3a8b29878fe222a9d7cbf645c975b12805704b0f39c7daa46033d22380f9828c eos.zip -dedff3eb408ea411812b8f46e6c6ed32bfbd97f61ec2b85a6be40373c0528256 eos.img -``` - -# v0.3.2 -## Highlights - - Autoscrolling for logs - - Improved connectivity between browser and Embassy - - Switch to Postgres for EOS database for better performance - - Multiple bug fixes and under-the-hood improvements - - Various UI/UX enhancements - - Removal of product keys - -Update Hash (SHA256): `d8ce908b06baee6420b45be1119e5eb9341ba8df920d1e255f94d1ffb7cc4de9` - -Image Hash (SHA256): `e035cd764e5ad9eb1c60e2f7bc3b9bd7248f42a91c69015c8a978a0f94b90bbb` - -Note: This image was uploaded as a gzipped POSIX sparse TAR file. The recommended command for unpacking it on systems that support sparse files is `tar --format=posix --sparse -zxvf eos.tar.gz` - -## What's Changed - - formatting by @dr-bonez in #1698 - - Update README.md by @kn0wmad in #1705 - - Update README.md by @dr-bonez in #1703 - - feat: migrate to Angular 14 and RxJS 7 by @waterplea in #1681 - - 0312 multiple FE by @MattDHill in #1712 - - Fix http requests by @MattDHill in #1717 - - Add build-essential to README.md by @chrisguida in #1716 - - write image to sparse-aware archive format by @dr-bonez in #1709 - - fix: Add modification to the max_user_watches by @Blu-J in #1695 - - [Feat] follow logs by @chrisguida in #1714 - - Update README.md by @dr-bonez in #1728 - - fix build for patch-db client for consistency by @elvece in #1722 - - fix cli install by @chrisguida in #1720 - - highlight instructions if not viewed by @MattDHill in #1731 - - Feat: HttpReader by @redragonx in #1733 - - Bugfix/dns by @dr-bonez in #1741 - - add x86 build and run unittests to backend pipeline by @moerketh in #1682 - - [Fix] websocket connecting and patchDB connection monitoring by @MattDHill in #1738 - - Set pipeline job timeouts and add ca-certificates to test container by @moerketh in #1753 - - Disable bluetooth properly #862 by @redragonx in #1745 - - [feat]: resumable downloads by @dr-bonez in #1746 - - Fix/empty properties by @elvece in #1764 - - use hostname from patchDB as default server name by @MattDHill in #1758 - - switch to postgresql by @dr-bonez in #1763 - - remove product key from setup flow by @MattDHill in #1750 - - pinning cargo dep versions for CLI by @redragonx in #1775 - - fix: Js deep dir by @Blu-J in #1784 - - 0.3.2 final cleanup by @dr-bonez in #1782 - - expect ui marketplace to be undefined by @MattDHill in #1787 - - fix init to exit on failure by @dr-bonez in #1788 - - fix search to return more accurate results by @MattDHill in #1792 - - update backend dependencies by @dr-bonez in #1796 - - use base64 for HTTP headers by @dr-bonez in #1795 - - fix: Bad cert of *.local.local is now fixed to correct. by @Blu-J in #1798 - - fix duplicate patch updates, add scroll button to setup success by @MattDHill in #1800 - - level_slider reclaiming that precious RAM memory by @k0gen in #1799 - - stop leaking avahi clients by @dr-bonez in #1802 - - fix: Deep is_parent was wrong and could be escapped by @Blu-J in #1801 - - prevent cfg str generation from running forever by @dr-bonez in #1804 - - better RPC error message by @MattDHill in #1803 - - Bugfix/marketplace add by @elvece in #1805 - - fix mrketplace swtiching by @MattDHill in #1810 - - clean up code and logs by @MattDHill in #1809 - - fix: Minor fix that matt wanted by @Blu-J in #1808 - - onion replace instead of adding tor repository by @k0gen in #1813 - - bank Start as embassy hostname from the begining by @k0gen in #1814 - - add descriptions to marketplace list page by @elvece in #1812 - - Fix/encryption by @elvece in #1811 - - restructure initialization by @dr-bonez in #1816 - - update license by @MattDHill in #1819 - - perform system rebuild after updating by @dr-bonez in #1820 - - ignore file not found error for delete by @dr-bonez in #1822 - - Multiple by @MattDHill in #1823 - - Bugfix/correctly package backend job by @moerketh in #1826 - - update patch-db by @dr-bonez in #1831 - - give name to logs file by @MattDHill in #1833 - - play song during update by @dr-bonez in #1832 - - Seed patchdb UI data by @elvece in #1835 - - update patch db and enable logging by @dr-bonez in #1837 - - reduce patch-db log level to warn by @dr-bonez in #1840 - - update ts matches to fix properties ordering bug by @elvece in #1843 - - handle multiple image tags having the same hash and increase timeout by @dr-bonez in #1844 - - retry pgloader up to 5x by @dr-bonez in #1845 - - show connection bar right away by @MattDHill in #1849 - - dizzy Rebranding to embassyOS by @k0gen in #1851 - - update patch db by @MattDHill in #1852 - - camera_flash screenshots update by @k0gen in #1853 - - disable concurrency and delete tmpdir before retry by @dr-bonez in #1846 - -## New Contributors - - - @redragonx made their first contribution in #1733 - - -# v0.3.1.1 -## What's Changed - - - whale2 docker stats fix by @k0gen in #1630 - - update backend dependencies by @dr-bonez in #1637 - - Fix/receipts health by @Blu-J in #1616 - - return correct error on failed os download by @dr-bonez in #1636 - - fix build by @dr-bonez in #1639 - - Update product.yaml by @dr-bonez in #1638 - - handle case where selected union enum is invalid after migration by @MattDHill in #1658 - - fix: Resolve fighting with NM by @Blu-J in #1660 - - sdk: don't allow mounts in inject actions by @chrisguida in #1653 - - feat: Variable args by @Blu-J in #1667 - - add readme to system-images folder by @elvece in #1665 - - Mask chars beyond 16 by @MattDHill in #1666 - - chore: Update to have the new version 0.3.1.1 by @Blu-J in #1668 - - feat: Make the rename effect by @Blu-J in #1669 - - fix migration, add logging by @dr-bonez in #1674 - - run build checks only when relevant FE changes by @elvece in #1664 - - trust local ca by @dr-bonez in #1670 - - lower log level for docker deser fallback message by @dr-bonez in #1672 - - refactor build process by @dr-bonez in #1675 - - chore: enable strict mode by @waterplea in #1569 - - draft releases notes for 0311 by @MattDHill in #1677 - - add standby mode by @dr-bonez in #1671 - - feat: atomic writing by @Blu-J in #1673 - - allow server.update to update to current version by @dr-bonez in #1679 - - allow falsey rpc response by @dr-bonez in #1680 - - issue notification when individual package restore fails by @dr-bonez in #1685 - - replace bang with question mark in html by @MattDHill in #1683 - - only validate mounts for inject if eos >=0.3.1.1 by @dr-bonez in #1686 - - add marketplace_url to backup metadata for service by @dr-bonez in #1688 - - marketplace published at for service by @MattDHill in #1689 - - sync data to fs before shutdown by @dr-bonez in #1690 - - messaging for restart, shutdown, rebuild by @MattDHill in #1691 - - honor shutdown from diagnostic ui by @dr-bonez in #1692 - - ask for sudo password immediately during make by @dr-bonez in #1693 - - sync blockdev after update by @dr-bonez in #1694 - - set Matt as default assignee by @MattDHill in #1697 - - NO_KEY for CI images by @dr-bonez in #1700 - - fix typo by @dr-bonez in #1702 - -# v0.3.1 -## What's Changed - - Feat bulk locking by @Blu-J in #1422 - - Switching SSH keys to start9 user by @k0gen in #1321 - - chore: Convert from ajv to ts-matches by @Blu-J in #1415 - - Fix/id params by @elvece in #1414 - - make nicer update sound by @ProofOfKeags in #1438 - - adds product key to error message in setup flow when there is mismatch by @dr-bonez in #1436 - - Update README.md to include yq by @cryptodread in #1385 - - yin_yang For the peace of mind yin_yang by @k0gen in #1444 - - Feature/update sound by @ProofOfKeags in #1439 - - Feature/script packing by @ProofOfKeags in #1435 - - rename ActionImplementation to PackageProcedure by @dr-bonez in #1448 - - Chore/warning cleanse by @ProofOfKeags in #1447 - - refactor packing to async by @ProofOfKeags in #1453 - - Add nginx config for proxy redirect by @yzernik in #1421 - - Proxy local frontend to remote backend by @elvece in #1452 - - Feat/js action by @Blu-J in #1437 - - Fix/making js work by @Blu-J in #1456 - - fix: Dependency vs dependents by @Blu-J in #1462 - - refactor: isolate network toast and login redirect to separate services by @waterplea in #1412 - - Fix links in CONTRIBUTING.md, update ToC by @BBlackwo in #1463 - - Feature/require script consistency by @ProofOfKeags in #1451 - - Chore/version 0 3 1 0 by @Blu-J in #1475 - - remove interactive TTY requirement from scripts by @moerketh in #1469 - - Disable view in marketplace button when side-loaded by @BBlackwo in #1471 - - Link to tor address on LAN setup page (#1277) by @BBlackwo in #1466 - - UI version updates and welcome message for 0.3.1 by @elvece in #1479 - - Update contribution and frontend readme by @BBlackwo in #1467 - - Clean up config by @MattDHill in #1484 - - Enable Control Groups for Docker containers by @k0gen in #1468 - - Fix/patch db unwrap remove by @Blu-J in #1481 - - handles spaces in working dir in make-image.sh by @moerketh in #1487 - - UI cosmetic improvements by @MattDHill in #1486 - - chore: fix the master by @Blu-J in #1495 - - generate unique ca names based off of server id by @ProofOfKeags in #1500 - - allow embassy-cli not as root by @dr-bonez in #1501 - - fix: potential fix for the docker leaking the errors and such by @Blu-J in #1496 - - Fix/memory leak docker by @Blu-J in #1505 - - fixes serialization of regex pattern + description by @ProofOfKeags in #1509 - - allow interactive TTY if available by @dr-bonez in #1508 - - fix "missing proxy" error in embassy-cli by @dr-bonez in #1516 - - Feat/js known errors by @Blu-J in #1514 - - fixes a bug where nginx will crash if eos goes into diagnostic mode a… by @dr-bonez in #1506 - - fix: restart/ uninstall sometimes didn't work by @Blu-J in #1527 - - add "error_for_status" to static file downloads by @dr-bonez in #1532 - - fixes #1169 by @dr-bonez in #1533 - - disable unnecessary services by @dr-bonez in #1535 - - chore: Update types to match embassyd by @Blu-J in #1539 - - fix: found a unsaturaded args fix by @Blu-J in #1540 - - chore: Update the lite types to include the union and enum by @Blu-J in #1542 - - Feat: Make the js check for health by @Blu-J in #1543 - - fix incorrect error message for deserialization in ValueSpecString by @dr-bonez in #1547 - - fix dependency/dependent id issue by @dr-bonez in #1546 - - add textarea to ValueSpecString by @dr-bonez in #1534 - - Feat/js metadata by @Blu-J in #1548 - - feat: uid/gid/mode added to metadata by @Blu-J in #1551 - - Strict null checks by @waterplea in #1464 - - fix backend builds for safe git config by @elvece in #1549 - - update should send version not version spec by @elvece in #1559 - - chore: Add tracing for debuging the js procedure slowness by @Blu-J in #1552 - - Reset password through setup wizard by @MattDHill in #1490 - - feat: Make sdk by @Blu-J in #1564 - - fix: Missing a feature flat cfg by @Blu-J in #1563 - - fixed sentence that didn't make sense by @BitcoinMechanic in #1565 - - refactor(patch-db): use PatchDB class declaratively by @waterplea in #1562 - - fix bugs with config and clean up dev options by @MattDHill in #1558 - - fix: Make it so we only need the password on the backup by @Blu-J in #1566 - - kill all sessions and remove ripple effect by @MattDHill in #1567 - - adjust service marketplace button for installation source relevance by @elvece in #1571 - - fix connection failure display monitoring and other style changes by @MattDHill in #1573 - - add dns server to embassy-os by @dr-bonez in #1572 - - Fix/mask generic inputs by @elvece in #1570 - - Fix/sideload icon type by @elvece in #1577 - - add avahi conditional compilation flags to dns by @dr-bonez in #1579 - - selective backups and better drive selection interface by @MattDHill in #1576 - - Feat/use modern tor by @kn0wmad in #1575 - - update welcome notes for 031 by @MattDHill in #1580 - - fix: Properties had a null description by @Blu-J in #1581 - - fix backup lock ordering by @dr-bonez in #1582 - - Bugfix/backup lock order by @dr-bonez in #1583 - - preload redacted and visibility hidden by @MattDHill in #1584 - - turn chevron red in config if error by @MattDHill in #1586 - - switch to utc by @dr-bonez in #1587 - - update patchdb for array patch fix by @elvece in #1588 - - filter package ids when backing up by @dr-bonez in #1589 - - add select/deselect all to backups and enum lists by @elvece in #1590 - - fix: Stop the buffer from dropped pre-maturly by @Blu-J in #1591 - - chore: commit the snapshots by @Blu-J in #1592 - - nest new entries and message updates better by @MattDHill in #1595 - - fix html parsing in logs by @elvece in #1598 - - don't crash service if io-format is set for main by @dr-bonez in #1599 - - strip html from colors from logs by @elvece in #1604 - - feat: fetch effect by @Blu-J in #1605 - - Fix/UI misc by @elvece in #1606 - - display bottom item in backup list and refactor for cleanliness by @MattDHill in #1609 - -# v0.3.0.3 -## What's Changed - - refactor: decompose app component by @waterplea in #1359 - - Update Makefile by @kn0wmad in #1400 - - ⬐ smarter wget by @k0gen in #1401 - - prevent the kernel from OOMKilling embassyd by @dr-bonez in #1402 - - attempt to heal when health check passes by @dr-bonez in #1420 - - Feat new locking by @Blu-J in #1384 - - version bump by @dr-bonez in #1423 - - Update server-show.page.ts by @chrisguida in #1424 - - Bump async from 2.6.3 to 2.6.4 in /frontend by @dependabot in #1426 - - Update index.html by @mirkoRainer in #1419 - -## New Contributors - - @dependabot made their first contribution in #1426 - - @mirkoRainer made their first contribution in #1419 - -# v0.3.0.2 -- Minor compatibility fixes - - #1392 - - #1390 - - #1388 - -# v0.3.0.1 -Minor bugfixes and performance improvements - -# v0.3.0 -- Websockets - - Real-time sync -- Patch DB - - Closely mirror FE and BE state. Most operating systems are connected to their GUI. Here it is served over the web. Patch DB and websockets serve to close the perceptual gap of this inherent challenge. -- Switch kernel from Raspbian to Ubuntu - - 64 bit - - Possibility for alternative hardware -- Merging of lifeline, agent, and appmgr into embassyd - - Elimination of Haskell in favor of pure Rust - - Unified API for interacting with the OS - - Easier to build from source -- OS (quarantined from OS and service data) - - Kernel/boot - - Persistent metadata (disk guid, product key) - - Rootfs (the os) - - Reserved (for updates) - swaps with rootfs -- Revamped OS updates - - Progress indicators - - Non-blocking - - Simple swap on reboot -- Revamped setup flow - - Elimination of Setup App (Apple/Google dependencies gone) - - Setup Wizard on http://embassy.local -- Revamped service config - - Dynamic, validated forms -- Diagnostic UI - - Missing disk, wrong disk, corrupt disk -- Turing complete API for actions, backup/restore, config, properties, notifications, health checks, and dependency requirements -- Optional, arbitrary inputs for actions -- Install, update, recover progress for apps -- Multiple interfaces - - E.g. rpc, p2p, ui -- Health checks - - Developer defined - - Internal, dependencies, and/or external -- Full Embassy backup (diff-based) -- External drive support/requirement - - Single at first - - Groundwork for extension and mirror drives -- Disk encryption - - Random key encrypted with static value - - Groundwork for swapping static value with chosen password -- Session Management - - List all active sessions - - Option to kill -- More robust and extensive logs -- Donations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 76dfec490..35f5d53aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,339 +1,119 @@ - - # Contributing to StartOS -First off, thanks for taking the time to contribute! ❤️ - -All types of contributions are encouraged and valued. See the -[Table of Contents](#table-of-contents) for different ways to help and details -about how this project handles them. Please make sure to read the relevant -section before making your contribution. It will make it a lot easier for us -maintainers and smooth out the experience for all involved. The community looks -forward to your contributions. 🎉 - -> And if you like the project, but just don't have time to contribute, that's -> fine. There are other easy ways to support the project and show your -> appreciation, which we would also be very happy about: -> -> - Star the project -> - Tweet about it -> - Refer this project in your project's readme -> - Mention the project at local meetups and tell your friends/colleagues -> - Buy a [Start9 server](https://start9.com) - - - -## Table of Contents - -- [I Have a Question](#i-have-a-question) -- [I Want To Contribute](#i-want-to-contribute) - - [Reporting Bugs](#reporting-bugs) - - [Suggesting Enhancements](#suggesting-enhancements) - - [Project Structure](#project-structure) - - [Your First Code Contribution](#your-first-code-contribution) - - [Setting Up Your Development Environment](#setting-up-your-development-environment) - - [Building The Image](#building-the-image) - - [Improving The Documentation](#improving-the-documentation) -- [Styleguides](#styleguides) - - [Formatting](#formatting) - - [Atomic Commits](#atomic-commits) - - [Commit Messages](#commit-messages) - - [Pull Requests](#pull-requests) - - [Rebasing Changes](#rebasing-changes) -- [Join The Discussion](#join-the-discussion) -- [Join The Project Team](#join-the-project-team) - -## I Have a Question - -> If you want to ask a question, we assume that you have read the available -> [Documentation](https://docs.start9labs.com). - -Before you ask a question, it is best to search for existing -[Issues](https://github.com/Start9Labs/start-os/issues) that might help you. -In case you have found a suitable issue and still need clarification, you can -write your question in this issue. It is also advisable to search the internet -for answers first. - -If you then still feel the need to ask a question and need clarification, we -recommend the following: - -- Open an [Issue](https://github.com/Start9Labs/start-os/issues/new). -- Provide as much context as you can about what you're running into. -- Provide project and platform versions, depending on what seems relevant. - -We will then take care of the issue as soon as possible. - - - -## I Want To Contribute - -> ### Legal Notice -> -> When contributing to this project, you must agree that you have authored 100% -> of the content, that you have the necessary rights to the content and that the -> content you contribute may be provided under the project license. - -### Reporting Bugs - - - -#### Before Submitting a Bug Report - -A good bug report shouldn't leave others needing to chase you up for more -information. Therefore, we ask you to investigate carefully, collect information -and describe the issue in detail in your report. Please complete the following -steps in advance to help us fix any potential bug as fast as possible. - -- Make sure that you are using the latest version. -- Determine if your bug is really a bug and not an error on your side e.g. using - incompatible environment components/versions (Make sure that you have read the - [documentation](https://start9.com/latest/user-manual). If you are looking for - support, you might want to check [this section](#i-have-a-question)). -- To see if other users have experienced (and potentially already solved) the - same issue you are having, check if there is not already a bug report existing - for your bug or error in the - [bug tracker](https://github.com/Start9Labs/start-os/issues?q=label%3Abug). -- Also make sure to search the internet (including Stack Overflow) to see if - users outside of the GitHub community have discussed the issue. -- Collect information about the bug: - - Stack trace (Traceback) - - Client OS, Platform and Version (Windows/Linux/macOS/iOS/Android, - Firefox/Tor Browser/Consulate) - - Version of the interpreter, compiler, SDK, runtime environment, package - manager, depending on what seems relevant. - - Possibly your input and the output - - Can you reliably reproduce the issue? And can you also reproduce it with - older versions? - - - -#### How Do I Submit a Good Bug Report? - -> You must never report security related issues, vulnerabilities or bugs to the -> issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by -> email to . - - - -We use GitHub issues to track bugs and errors. If you run into an issue with the -project: - -- Open an [Issue](https://github.com/Start9Labs/start-os/issues/new/choose) - selecting the appropriate type. -- Explain the behavior you would expect and the actual behavior. -- Please provide as much context as possible and describe the _reproduction - steps_ that someone else can follow to recreate the issue on their own. This - usually includes your code. For good bug reports you should isolate the - problem and create a reduced test case. -- Provide the information you collected in the previous section. - -Once it's filed: - -- The project team will label the issue accordingly. -- A team member will try to reproduce the issue with your provided steps. If - there are no reproduction steps or no obvious way to reproduce the issue, the - team will ask you for those steps and mark the issue as `Question`. Bugs with - the `Question` tag will not be addressed until they are answered. -- If the team is able to reproduce the issue, it will be marked a scoping level - tag, as well as possibly other tags (such as `Security`), and the issue will - be left to be [implemented by someone](#your-first-code-contribution). - - - -### Suggesting Enhancements - -This section guides you through submitting an enhancement suggestion for StartOS, **including completely new features and minor improvements to existing -functionality**. Following these guidelines will help maintainers and the -community to understand your suggestion and find related suggestions. +This guide is for contributing to the StartOS. If you are interested in packaging a service for StartOS, visit the [service packaging guide](https://docs.start9.com/latest/developer-docs/). If you are interested in promoting, providing technical support, creating tutorials, or helping in other ways, please visit the [Start9 website](https://start9.com/contribute). - -#### Before Submitting an Enhancement +## Collaboration -- Make sure that you are using the latest version. -- Read the [documentation](https://start9.com/latest/user-manual) carefully and - find out if the functionality is already covered, maybe by an individual - configuration. -- Perform a [search](https://github.com/Start9Labs/start-os/issues) to see if - the enhancement has already been suggested. If it has, add a comment to the - existing issue instead of opening a new one. -- Find out whether your idea fits with the scope and aims of the project. It's - up to you to make a strong case to convince the project's developers of the - merits of this feature. Keep in mind that we want features that will be useful - to the majority of our users and not just a small subset. If you're just - targeting a minority of users, consider writing an add-on/plugin library. +- [Matrix](https://matrix.to/#/#community-dev:matrix.start9labs.com) +- [Telegram](https://t.me/start9_labs/47471) - +## Project Structure -#### How Do I Submit a Good Enhancement Suggestion? - -Enhancement suggestions are tracked as -[GitHub issues](https://github.com/Start9Labs/start-os/issues). +```bash +/ +├── assets/ +├── core/ +├── build/ +├── debian/ +├── web/ +├── image-recipe/ +├── patch-db +└── system-images/ +``` +#### assets +screenshots for the StartOS README -- Use a **clear and descriptive title** for the issue to identify the - suggestion. -- Provide a **step-by-step description of the suggested enhancement** in as many - details as possible. -- **Describe the current behavior** and **explain which behavior you expected to - see instead** and why. At this point you can also tell which alternatives do - not work for you. -- You may want to **include screenshots and animated GIFs** which help you - demonstrate the steps or point out the part which the suggestion is related - to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on - macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) - or [this tool](https://github.com/GNOME/byzanz) on Linux. - -- **Explain why this enhancement would be useful** to most StartOS users. You - may also want to point out the other projects that solved it better and which - could serve as inspiration. +#### core +An API, daemon (startd), CLI (start-cli), and SDK (start-sdk) that together provide the core functionality of StartOS. - +#### build +Auxiliary files and scripts to include in deployed StartOS images -### Project Structure +#### debian +Maintainer scripts for the StartOS Debian package -StartOS is composed of the following components. Please visit the README for -each component to understand the dependency requirements and installation -instructions. +#### web +Web UIs served under various conditions and used to interact with StartOS APIs. -- [`backend`](backend/README.md) (Rust) is a command line utility, daemon, and - software development kit that sets up and manages services and their - environments, provides the interface for the ui, manages system state, and - provides utilities for packaging services for StartOS. -- [`build`](build/README.md) contains scripts and necessary for deploying - StartOS to a debian/raspbian system. -- [`frontend`](frontend/README.md) (Typescript Ionic Angular) is the code that - is deployed to the browser to provide the user interface for StartOS. - - `projects/ui` - Code for the user interface that is displayed when StartOS - is running normally. - - `projects/setup-wizard`(frontend/README.md) - Code for the user interface - that is displayed during the setup and recovery process for StartOS. - - `projects/diagnostic-ui` - Code for the user interface that is displayed - when something has gone wrong with starting up StartOS, which provides - helpful debugging tools. -- `libs` (Rust) is a set of standalone crates that were separated out of - `backend` for the purpose of portability -- `patch-db` - A diff based data store that is used to synchronize data between - the front and backend. - - Notably, `patch-db` has a - [client](https://github.com/Start9Labs/patch-db/tree/master/client) with its - own dependency and installation requirements. -- `system-images` - (Docker, Rust) A suite of utility Docker images that are - preloaded with StartOS to assist with functions relating to services (eg. - configuration, backups, health checks). +#### image-recipe +Scripts for building StartOS images -### Your First Code Contribution +#### patch-db (submodule) +A diff based data store used to synchronize data between the web interfaces and server. -#### Setting Up Your Development Environment +#### system-images +Docker images that assist with creating backups. -First, clone the StartOS repository and from the project root, pull in the -submodules for dependent libraries. +## Environment Setup +#### Clone the StartOS repository ```sh git clone https://github.com/Start9Labs/start-os.git -git submodule update --init --recursive +cd start-os ``` -Depending on which component of the ecosystem you are interested in contributing -to, follow the installation requirements listed in that component's README -(linked [above](#project-structure)) - -#### Building The Raspberry Pi Image - -This step is for setting up an environment in which to test your code changes if -you do not yet have a StartOS. - -- Requirements - - `ext4fs` (available if running on the Linux kernel) - - [Docker](https://docs.docker.com/get-docker/) - - GNU Make -- Building - - see setup instructions [here](build/README.md) - - run `make startos-raspi.img ARCH=aarch64` from the project root - -### Improving The Documentation - -You can find the repository for Start9's documentation -[here](https://github.com/Start9Labs/documentation). If there is something you -would like to see added, let us know, or create an issue yourself. Welcome are -contributions for lacking or incorrect information, broken links, requested -additions, or general style improvements. - -Contributions in the form of setup guides for integrations with external -applications are highly encouraged. If you struggled through a process and would -like to share your steps with others, check out the docs for each -[service](https://github.com/Start9Labs/documentation/blob/master/source/user-manuals/available-services/index.rst) -we support. The wrapper repos contain sections for adding integration guides, -such as this -[one](https://github.com/Start9Labs/bitcoind-wrapper/tree/master/docs). These -not only help out others in the community, but inform how we can create a more -seamless and intuitive experience. - -## Styleguides - -### Formatting - -Each component of StartOS contains its own style guide. Code must be formatted -with the formatter designated for each component. These are outlined within each -component folder's README. - -### Atomic Commits - -Commits -[should be atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention) -and diffs should be easy to read. Do not mix any formatting fixes or code moves -with actual code changes. - -### Commit Messages - -If a commit touches only 1 component, prefix the message with the affected -component. i.e. `backend: update to tokio v0.3`. - -### Pull Requests - -The body of a pull request should contain sufficient description of what the -changes do, as well as a justification. You should include references to any -relevant [issues](https://github.com/Start9Labs/start-os/issues). - -### Rebasing Changes - -When a pull request conflicts with the target branch, you may be asked to rebase -it on top of the current target branch. The `git rebase` command will take care -of rebuilding your commits on top of the new base. - -This project aims to have a clean git history, where code changes are only made -in non-merge commits. This simplifies auditability because merge commits can be -assumed to not contain arbitrary code changes. - -## Join The Discussion - -Current or aspiring contributors? Join our community developer -[Matrix channel](https://matrix.to/#/#community-dev:matrix.start9labs.com). - -Just interested in or using the project? Join our community -[Telegram](https://t.me/start9_labs) or -[Matrix](https://matrix.to/#/#community:matrix.start9labs.com). - -## Join The Project Team - -Interested in becoming a part of the Start9 Labs team? Send an email to - - - - -## Attribution +#### Load the PatchDB submodule +```sh +git submodule update --init --recursive +``` -This guide is based on the **contributing-gen**. -[Make your own](https://github.com/bttger/contributing-gen)! +#### Continue to your project of interest for additional instructions: +- [`core`](core/README.md) +- [`web-interfaces`](web-interfaces/README.md) +- [`build`](build/README.md) +- [`patch-db`](https://github.com/Start9Labs/patch-db) + +## Building +This project uses [GNU Make](https://www.gnu.org/software/make/) to build its components. To build any specific component, simply run `make ` replacing `` with the name of the target you'd like to build + +### Requirements +- [GNU Make](https://www.gnu.org/software/make/) +- [Docker](https://docs.docker.com/get-docker/) +- [NodeJS v18.15.0](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) +- [sed](https://www.gnu.org/software/sed/) +- [grep](https://www.gnu.org/software/grep/) +- [awk](https://www.gnu.org/software/gawk/) +- [jq](https://jqlang.github.io/jq/) +- [gzip](https://www.gnu.org/software/gzip/) +- [brotli](https://github.com/google/brotli) + +### Environment variables +- `PLATFORM`: which platform you would like to build for. Must be one of `x86_64`, `x86_64-nonfree`, `aarch64`, `aarch64-nonfree`, `raspberrypi` + - NOTE: `nonfree` images are for including `nonfree` firmware packages in the built ISO +- `ENVIRONMENT`: a hyphen separated set of feature flags to enable + - `dev`: enables password ssh (INSECURE!) and does not compress frontends + - `unstable`: enables assertions that will cause errors on unexpected inconsistencies that are undesirable in production use either for performance or reliability reasons + - `docker`: use `docker` instead of `podman` +- `GIT_BRANCH_AS_HASH`: set to `1` to use the current git branch name as the git hash so that the project does not need to be rebuilt on each commit + +### Useful Make Targets +- `iso`: Create a full `.iso` image + - Only possible from Debian + - Not available for `PLATFORM=raspberrypi` + - Additional Requirements: + - [debspawn](https://github.com/lkhq/debspawn) +- `img`: Create a full `.img` image + - Only possible from Debian + - Only available for `PLATFORM=raspberrypi` + - Additional Requirements: + - [debspawn](https://github.com/lkhq/debspawn) +- `format`: Run automatic code formatting for the project + - Additional Requirements: + - [rust](https://rustup.rs/) +- `test`: Run automated tests for the project + - Additional Requirements: + - [rust](https://rustup.rs/) +- `update`: Deploy the current working project to a device over ssh as if through an over-the-air update + - Requires an argument `REMOTE` which is the ssh address of the device, i.e. `start9@192.168.122.2` +- `reflash`: Deploy the current working project to a device over ssh as if using a live `iso` image to reflash it + - Requires an argument `REMOTE` which is the ssh address of the device, i.e. `start9@192.168.122.2` +- `update-overlay`: Deploy the current working project to a device over ssh to the in-memory overlay without restarting it + - WARNING: changes will be reverted after the device is rebooted + - WARNING: changes to `init` will not take effect as the device is already initialized + - Requires an argument `REMOTE` which is the ssh address of the device, i.e. `start9@192.168.122.2` +- `wormhole`: Deploy the `startbox` to a device using [magic-wormhole](https://github.com/magic-wormhole/magic-wormhole) + - When the build it complete will emit a command to paste into the shell of the device to upgrade it + - Additional Requirements: + - [magic-wormhole](https://github.com/magic-wormhole/magic-wormhole) +- `clean`: Delete all compiled artifacts \ No newline at end of file diff --git a/Makefile b/Makefile index ec2183178..b91cc4c0f 100644 --- a/Makefile +++ b/Makefile @@ -6,26 +6,26 @@ BASENAME := $(shell ./basename.sh) PLATFORM := $(shell if [ -f ./PLATFORM.txt ]; then cat ./PLATFORM.txt; else echo unknown; fi) ARCH := $(shell if [ "$(PLATFORM)" = "raspberrypi" ]; then echo aarch64; else echo $(PLATFORM) | sed 's/-nonfree$$//g'; fi) IMAGE_TYPE=$(shell if [ "$(PLATFORM)" = raspberrypi ]; then echo img; else echo iso; fi) -EMBASSY_BINS := backend/target/$(ARCH)-unknown-linux-gnu/release/startbox libs/target/aarch64-unknown-linux-musl/release/embassy_container_init libs/target/x86_64-unknown-linux-musl/release/embassy_container_init -EMBASSY_UIS := frontend/dist/raw/ui frontend/dist/raw/setup-wizard frontend/dist/raw/diagnostic-ui frontend/dist/raw/install-wizard +BINS := core/target/$(ARCH)-unknown-linux-gnu/release/startbox core/target/aarch64-unknown-linux-musl/release/container-init core/target/x86_64-unknown-linux-musl/release/container-init +WEB_UIS := web/dist/raw/ui web/dist/raw/setup-wizard web/dist/raw/diagnostic-ui web/dist/raw/install-wizard BUILD_SRC := $(shell git ls-files build) build/lib/depends build/lib/conflicts DEBIAN_SRC := $(shell git ls-files debian/) IMAGE_RECIPE_SRC := $(shell git ls-files image-recipe/) -EMBASSY_SRC := backend/startd.service $(BUILD_SRC) +STARTD_SRC := core/startos/startd.service $(BUILD_SRC) COMPAT_SRC := $(shell git ls-files system-images/compat/) UTILS_SRC := $(shell git ls-files system-images/utils/) BINFMT_SRC := $(shell git ls-files system-images/binfmt/) -BACKEND_SRC := $(shell git ls-files backend) $(shell git ls-files --recurse-submodules patch-db) $(shell git ls-files libs) frontend/dist/static -FRONTEND_SHARED_SRC := $(shell git ls-files frontend/projects/shared) $(shell ls -p frontend/ | grep -v / | sed 's/^/frontend\//g') frontend/node_modules frontend/config.json patch-db/client/dist frontend/patchdb-ui-seed.json -FRONTEND_UI_SRC := $(shell git ls-files frontend/projects/ui) -FRONTEND_SETUP_WIZARD_SRC := $(shell git ls-files frontend/projects/setup-wizard) -FRONTEND_DIAGNOSTIC_UI_SRC := $(shell git ls-files frontend/projects/diagnostic-ui) -FRONTEND_INSTALL_WIZARD_SRC := $(shell git ls-files frontend/projects/install-wizard) +CORE_SRC := $(shell git ls-files core) $(shell git ls-files --recurse-submodules patch-db) web/dist/static web/patchdb-ui-seed.json $(GIT_HASH_FILE) +WEB_SHARED_SRC := $(shell git ls-files web/projects/shared) $(shell ls -p web/ | grep -v / | sed 's/^/web\//g') web/node_modules web/config.json patch-db/client/dist web/patchdb-ui-seed.json +WEB_UI_SRC := $(shell git ls-files web/projects/ui) +WEB_SETUP_WIZARD_SRC := $(shell git ls-files web/projects/setup-wizard) +WEB_DIAGNOSTIC_UI_SRC := $(shell git ls-files web/projects/diagnostic-ui) +WEB_INSTALL_WIZARD_SRC := $(shell git ls-files web/projects/install-wizard) PATCH_DB_CLIENT_SRC := $(shell git ls-files --recurse-submodules patch-db/client) GZIP_BIN := $(shell which pigz || which gzip) TAR_BIN := $(shell which gtar || which tar) -COMPILED_TARGETS := $(EMBASSY_BINS) system-images/compat/docker-images/$(ARCH).tar system-images/utils/docker-images/$(ARCH).tar system-images/binfmt/docker-images/$(ARCH).tar -ALL_TARGETS := $(EMBASSY_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) $(VERSION_FILE) $(COMPILED_TARGETS) $(shell if [ "$(PLATFORM)" = "raspberrypi" ]; then echo cargo-deps/aarch64-unknown-linux-gnu/release/pi-beep; fi) $(shell /bin/bash -c 'if [[ "${ENVIRONMENT}" =~ (^|-)unstable($$|-) ]]; then echo cargo-deps/$(ARCH)-unknown-linux-gnu/release/tokio-console; fi') $(PLATFORM_FILE) +COMPILED_TARGETS := $(BINS) system-images/compat/docker-images/$(ARCH).tar system-images/utils/docker-images/$(ARCH).tar system-images/binfmt/docker-images/$(ARCH).tar +ALL_TARGETS := $(STARTD_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) $(VERSION_FILE) $(COMPILED_TARGETS) $(shell if [ "$(PLATFORM)" = "raspberrypi" ]; then echo cargo-deps/aarch64-unknown-linux-gnu/release/pi-beep; fi) $(shell /bin/bash -c 'if [[ "${ENVIRONMENT}" =~ (^|-)unstable($$|-) ]]; then echo cargo-deps/$(ARCH)-unknown-linux-gnu/release/tokio-console; fi') $(PLATFORM_FILE) ifeq ($(REMOTE),) mkdir = mkdir -p $1 @@ -48,7 +48,7 @@ endif .DELETE_ON_ERROR: -.PHONY: all metadata install clean format sdk snapshots frontends ui backend reflash deb $(IMAGE_TYPE) squashfs sudo wormhole +.PHONY: all metadata install clean format sdk snapshots uis ui reflash deb $(IMAGE_TYPE) squashfs sudo wormhole test all: $(ALL_TARGETS) @@ -60,12 +60,11 @@ sudo: clean: rm -f system-images/**/*.tar rm -rf system-images/compat/target - rm -rf backend/target - rm -rf frontend/.angular - rm -f frontend/config.json - rm -rf frontend/node_modules - rm -rf frontend/dist - rm -rf libs/target + rm -rf core/target + rm -rf web/.angular + rm -f web/config.json + rm -rf web/node_modules + rm -rf web/dist rm -rf patch-db/client/node_modules rm -rf patch-db/client/dist rm -rf patch-db/target @@ -79,11 +78,14 @@ clean: rm -f VERSION.txt format: - cd backend && cargo +nightly fmt - cd libs && cargo +nightly fmt + cd core && cargo +nightly fmt + +test: $(BACKEND_SRC) $(ENVIRONMENT_FILE) + cd backend && cargo build && cargo test + cd libs && cargo test sdk: - cd backend/ && ./install-sdk.sh + cd core && ./install-sdk.sh deb: results/$(BASENAME).deb @@ -103,7 +105,7 @@ results/$(BASENAME).$(IMAGE_TYPE) results/$(BASENAME).squashfs: $(IMAGE_RECIPE_S # For creating os images. DO NOT USE install: $(ALL_TARGETS) $(call mkdir,$(DESTDIR)/usr/bin) - $(call cp,backend/target/$(ARCH)-unknown-linux-gnu/release/startbox,$(DESTDIR)/usr/bin/startbox) + $(call cp,core/target/$(ARCH)-unknown-linux-gnu/release/startbox,$(DESTDIR)/usr/bin/startbox) $(call ln,/usr/bin/startbox,$(DESTDIR)/usr/bin/startd) $(call ln,/usr/bin/startbox,$(DESTDIR)/usr/bin/start-cli) $(call ln,/usr/bin/startbox,$(DESTDIR)/usr/bin/start-sdk) @@ -114,7 +116,7 @@ install: $(ALL_TARGETS) if /bin/bash -c '[[ "${ENVIRONMENT}" =~ (^|-)unstable($$|-) ]]'; then $(call cp,cargo-deps/$(ARCH)-unknown-linux-gnu/release/tokio-console,$(DESTDIR)/usr/bin/tokio-console); fi $(call mkdir,$(DESTDIR)/lib/systemd/system) - $(call cp,backend/startd.service,$(DESTDIR)/lib/systemd/system/startd.service) + $(call cp,core/startos/startd.service,$(DESTDIR)/lib/systemd/system/startd.service) $(call mkdir,$(DESTDIR)/usr/lib) $(call rm,$(DESTDIR)/usr/lib/startos) @@ -126,8 +128,8 @@ install: $(ALL_TARGETS) $(call cp,VERSION.txt,$(DESTDIR)/usr/lib/startos/VERSION.txt) $(call mkdir,$(DESTDIR)/usr/lib/startos/container) - $(call cp,libs/target/aarch64-unknown-linux-musl/release/embassy_container_init,$(DESTDIR)/usr/lib/startos/container/embassy_container_init.arm64) - $(call cp,libs/target/x86_64-unknown-linux-musl/release/embassy_container_init,$(DESTDIR)/usr/lib/startos/container/embassy_container_init.amd64) + $(call cp,core/target/aarch64-unknown-linux-musl/release/container-init,$(DESTDIR)/usr/lib/startos/container/container-init.arm64) + $(call cp,core/target/x86_64-unknown-linux-musl/release/container-init,$(DESTDIR)/usr/lib/startos/container/container-init.amd64) $(call mkdir,$(DESTDIR)/usr/lib/startos/system-images) $(call cp,system-images/compat/docker-images/$(ARCH).tar,$(DESTDIR)/usr/lib/startos/system-images/compat.tar) @@ -143,8 +145,8 @@ update-overlay: $(ALL_TARGETS) $(MAKE) install REMOTE=$(REMOTE) SSHPASS=$(SSHPASS) PLATFORM=$(PLATFORM) $(call ssh,"sudo systemctl start startd") -wormhole: backend/target/$(ARCH)-unknown-linux-gnu/release/startbox - @wormhole send backend/target/$(ARCH)-unknown-linux-gnu/release/startbox 2>&1 | awk -Winteractive '/wormhole receive/ { printf "sudo /usr/lib/startos/scripts/chroot-and-upgrade \"cd /usr/bin && rm startbox && wormhole receive --accept-file %s && chmod +x startbox\"\n", $$3 }' +wormhole: core/target/$(ARCH)-unknown-linux-gnu/release/startbox + @wormhole send core/target/$(ARCH)-unknown-linux-gnu/release/startbox 2>&1 | awk -Winteractive '/wormhole receive/ { printf "sudo /usr/lib/startos/scripts/chroot-and-upgrade \"cd /usr/bin && rm startbox && wormhole receive --accept-file %s && chmod +x startbox\"\n", $$3 }' update: $(ALL_TARGETS) @if [ -z "$(REMOTE)" ]; then >&2 echo "Must specify REMOTE" && false; fi @@ -164,7 +166,7 @@ upload-ota: results/$(BASENAME).squashfs build/lib/depends build/lib/conflicts: build/dpkg-deps/* build/dpkg-deps/generate.sh -system-images/compat/docker-images/$(ARCH).tar: $(COMPAT_SRC) backend/Cargo.lock +system-images/compat/docker-images/$(ARCH).tar: $(COMPAT_SRC) core/Cargo.lock cd system-images/compat && make docker-images/$(ARCH).tar && touch docker-images/$(ARCH).tar system-images/utils/docker-images/$(ARCH).tar: $(UTILS_SRC) @@ -173,55 +175,55 @@ system-images/utils/docker-images/$(ARCH).tar: $(UTILS_SRC) system-images/binfmt/docker-images/$(ARCH).tar: $(BINFMT_SRC) cd system-images/binfmt && make docker-images/$(ARCH).tar && touch docker-images/$(ARCH).tar -snapshots: libs/snapshot_creator/Cargo.toml - cd libs/ && ./build-v8-snapshot.sh - cd libs/ && ./build-arm-v8-snapshot.sh +snapshots: core/snapshot-creator/Cargo.toml + cd core/ && ARCH=aarch64 ./build-v8-snapshot.sh + cd core/ && ARCH=x86_64 ./build-v8-snapshot.sh -$(EMBASSY_BINS): $(BACKEND_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) frontend/patchdb-ui-seed.json | sudo - cd backend && ARCH=$(ARCH) ./build-prod.sh - touch $(EMBASSY_BINS) +$(BINS): $(CORE_SRC) $(ENVIRONMENT_FILE) | sudo + cd core && ARCH=$(ARCH) ./build-prod.sh + touch $(BINS) -frontend/node_modules: frontend/package.json - npm --prefix frontend ci +web/node_modules: web/package.json + npm --prefix web ci -frontend/dist/raw/ui: $(FRONTEND_UI_SRC) $(FRONTEND_SHARED_SRC) - npm --prefix frontend run build:ui +web/dist/raw/ui: $(WEB_UI_SRC) $(WEB_SHARED_SRC) + npm --prefix web run build:ui -frontend/dist/raw/setup-wizard: $(FRONTEND_SETUP_WIZARD_SRC) $(FRONTEND_SHARED_SRC) - npm --prefix frontend run build:setup +web/dist/raw/setup-wizard: $(WEB_SETUP_WIZARD_SRC) $(WEB_SHARED_SRC) + npm --prefix web run build:setup -frontend/dist/raw/diagnostic-ui: $(FRONTEND_DIAGNOSTIC_UI_SRC) $(FRONTEND_SHARED_SRC) - npm --prefix frontend run build:dui +web/dist/raw/diagnostic-ui: $(WEB_DIAGNOSTIC_UI_SRC) $(WEB_SHARED_SRC) + npm --prefix web run build:dui -frontend/dist/raw/install-wizard: $(FRONTEND_INSTALL_WIZARD_SRC) $(FRONTEND_SHARED_SRC) - npm --prefix frontend run build:install-wiz +web/dist/raw/install-wizard: $(WEB_INSTALL_WIZARD_SRC) $(WEB_SHARED_SRC) + npm --prefix web run build:install-wiz -frontend/dist/static: $(EMBASSY_UIS) $(ENVIRONMENT_FILE) +web/dist/static: $(WEB_UIS) $(ENVIRONMENT_FILE) ./compress-uis.sh -frontend/config.json: $(GIT_HASH_FILE) frontend/config-sample.json - jq '.useMocks = false' frontend/config-sample.json | jq '.gitHash = "$(shell cat GIT_HASH.txt)"' > frontend/config.json +web/config.json: $(GIT_HASH_FILE) web/config-sample.json + jq '.useMocks = false' web/config-sample.json | jq '.gitHash = "$(shell cat GIT_HASH.txt)"' > web/config.json -frontend/patchdb-ui-seed.json: frontend/package.json - jq '."ack-welcome" = $(shell jq '.version' frontend/package.json)' frontend/patchdb-ui-seed.json > ui-seed.tmp - mv ui-seed.tmp frontend/patchdb-ui-seed.json +web/patchdb-ui-seed.json: web/package.json + jq '."ack-welcome" = $(shell jq '.version' web/package.json)' web/patchdb-ui-seed.json > ui-seed.tmp + mv ui-seed.tmp web/patchdb-ui-seed.json patch-db/client/node_modules: patch-db/client/package.json npm --prefix patch-db/client ci patch-db/client/dist: $(PATCH_DB_CLIENT_SRC) patch-db/client/node_modules ! test -d patch-db/client/dist || rm -rf patch-db/client/dist - npm --prefix frontend run build:deps + npm --prefix web run build:deps # used by github actions compiled-$(ARCH).tar: $(COMPILED_TARGETS) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) $(VERSION_FILE) tar -cvf $@ $^ -# this is a convenience step to build all frontends - it is not referenced elsewhere in this file -frontends: $(EMBASSY_UIS) +# this is a convenience step to build all web uis - it is not referenced elsewhere in this file +uis: $(WEB_UIS) # this is a convenience step to build the UI -ui: frontend/dist/raw/ui +ui: web/dist/raw/ui cargo-deps/aarch64-unknown-linux-gnu/release/pi-beep: ARCH=aarch64 ./build-cargo-dep.sh pi-beep diff --git a/README.md b/README.md index db3c24e73..8383498b1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- StartOS Logo + StartOS Logo

StartOS

GitHub release (with filter) diff --git a/backend/.gitignore b/backend/.gitignore deleted file mode 100644 index d4898965a..000000000 --- a/backend/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -/target -**/*.rs.bk -.DS_Store -.vscode -secrets.db -*.s9pk -*.sqlite3 -.env -.editorconfig -proptest-regressions/* diff --git a/backend/README.md b/backend/README.md deleted file mode 100644 index 01d0b2a4d..000000000 --- a/backend/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# StartOS Backend - -- Requirements: - - [Install Rust](https://rustup.rs) - - Recommended: [rust-analyzer](https://rust-analyzer.github.io/) - - [Docker](https://docs.docker.com/get-docker/) - - [Rust ARM64 Build Container](https://github.com/Start9Labs/rust-arm-builder) - - Mac `brew install gnu-tar` -- Scripts (run within the `./backend` directory) - - `build-prod.sh` - compiles a release build of the artifacts for running on - ARM64 -- A Linux computer or VM - -## Structure - -The StartOS backend is packed into a single binary `startbox` that is symlinked under -several different names for different behaviour: - -- startd: This is the main workhorse of StartOS - any new functionality you - want will likely go here -- start-cli: This is a CLI tool that will allow you to issue commands to - startd and control it similarly to the UI -- start-sdk: This is a CLI tool that aids in building and packaging services - you wish to deploy to StartOS - -Finally there is a library `startos` that supports all of these tools. - -See [here](/backend/Cargo.toml) for details. - -## Building - -You can build the entire operating system image using `make` from the root of -the StartOS project. This will subsequently invoke the build scripts above to -actually create the requisite binaries and put them onto the final operating -system image. - -## Questions - -If you have questions about how various pieces of the backend system work. Open -an issue and tag the following people - -- dr-bonez diff --git a/backend/build-portable.sh b/backend/build-portable.sh deleted file mode 100755 index 9b1b96f34..000000000 --- a/backend/build-portable.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -set -e -shopt -s expand_aliases - -if [ "$0" != "./build-portable.sh" ]; then - >&2 echo "Must be run from backend directory" - exit 1 -fi - -USE_TTY= -if tty -s; then - USE_TTY="-it" -fi - -alias 'rust-musl-builder'='docker run $USE_TTY --rm -v "$HOME"/.cargo/registry:/root/.cargo/registry -v "$(pwd)":/home/rust/src start9/rust-musl-cross:x86_64-musl' - -cd .. -rust-musl-builder sh -c "(cd backend && cargo +beta build --release --target=x86_64-unknown-linux-musl --no-default-features --locked)" -cd backend - -sudo chown -R $USER target -sudo chown -R $USER ~/.cargo \ No newline at end of file diff --git a/backend/install-sdk.sh b/backend/install-sdk.sh deleted file mode 100755 index a5d9b31b6..000000000 --- a/backend/install-sdk.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -set -e -shopt -s expand_aliases - -if [ "$0" != "./install-sdk.sh" ]; then - >&2 echo "Must be run from backend directory" - exit 1 -fi - -frontend="../frontend/dist/static" -[ -d "$frontend" ] || mkdir -p "$frontend" - -if [ -z "$PLATFORM" ]; then - export PLATFORM=$(uname -m) -fi - -cargo install --path=. --no-default-features --features=js_engine,sdk,cli --locked -startbox_loc=$(which startbox) -ln -sf $startbox_loc $(dirname $startbox_loc)/start-cli -ln -sf $startbox_loc $(dirname $startbox_loc)/start-sdk diff --git a/backend/test/js_action_execute/package-data/volumes/test-package/data/main/pem-chown/deep/123/test.txt b/backend/test/js_action_execute/package-data/volumes/test-package/data/main/pem-chown/deep/123/test.txt deleted file mode 100644 index 5e1c309da..000000000 --- a/backend/test/js_action_execute/package-data/volumes/test-package/data/main/pem-chown/deep/123/test.txt +++ /dev/null @@ -1 +0,0 @@ -Hello World \ No newline at end of file diff --git a/check-version.sh b/check-version.sh index 72b56a3e8..3e0c9ddb2 100755 --- a/check-version.sh +++ b/check-version.sh @@ -1,6 +1,6 @@ #!/bin/bash -FE_VERSION="$(cat frontend/package.json | grep '"version"' | sed 's/[ \t]*"version":[ \t]*"\([^"]*\)",/\1/')" +FE_VERSION="$(cat web/package.json | grep '"version"' | sed 's/[ \t]*"version":[ \t]*"\([^"]*\)",/\1/')" # TODO: Validate other version sources - backend/Cargo.toml, backend/src/version/mod.rs diff --git a/compress-uis.sh b/compress-uis.sh index 1a7ea9124..3ca6cccf0 100755 --- a/compress-uis.sh +++ b/compress-uis.sh @@ -1,14 +1,16 @@ #!/bin/bash +cd "$(dirname "${BASH_SOURCE[0]}")" + set -e -rm -rf frontend/dist/static +rm -rf web/dist/static if ! [[ "$ENVIRONMENT" =~ (^|-)dev($|-) ]]; then - find frontend/dist/raw -type f -not -name '*.gz' -and -not -name '*.br' | xargs -n 1 -P 0 gzip -kf - find frontend/dist/raw -type f -not -name '*.gz' -and -not -name '*.br' | xargs -n 1 -P 0 brotli -kf + find web/dist/raw -type f -not -name '*.gz' -and -not -name '*.br' | xargs -n 1 -P 0 gzip -kf + find web/dist/raw -type f -not -name '*.gz' -and -not -name '*.br' | xargs -n 1 -P 0 brotli -kf - for file in $(find frontend/dist/raw -type f -not -name '*.gz' -and -not -name '*.br'); do + for file in $(find web/dist/raw -type f -not -name '*.gz' -and -not -name '*.br'); do raw_size=$(du $file | awk '{print $1 * 512}') gz_size=$(du $file.gz | awk '{print $1 * 512}') br_size=$(du $file.br | awk '{print $1 * 512}') @@ -21,4 +23,4 @@ if ! [[ "$ENVIRONMENT" =~ (^|-)dev($|-) ]]; then done fi -cp -r frontend/dist/raw frontend/dist/static \ No newline at end of file +cp -r web/dist/raw web/dist/static \ No newline at end of file diff --git a/libs/.gitignore b/core/.gitignore similarity index 76% rename from libs/.gitignore rename to core/.gitignore index d4898965a..ad8368a86 100644 --- a/libs/.gitignore +++ b/core/.gitignore @@ -7,4 +7,4 @@ secrets.db *.sqlite3 .env .editorconfig -proptest-regressions/* +proptest-regressions/**/* diff --git a/backend/Cargo.lock b/core/Cargo.lock similarity index 92% rename from backend/Cargo.lock rename to core/Cargo.lock index 4aafa0aa8..c674ed77f 100644 --- a/backend/Cargo.lock +++ b/core/Cargo.lock @@ -42,25 +42,26 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if 1.0.0", - "getrandom 0.2.10", + "getrandom 0.2.11", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -154,7 +155,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -201,7 +202,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -212,7 +213,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -330,9 +331,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -461,6 +462,19 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if 1.0.0", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -499,9 +513,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da74e2b81409b1b743f8f0c62cc6254afefb8b8e50bbfe3735550f7aeefa3448" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -527,9 +541,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856" dependencies = [ "libc", ] @@ -572,11 +586,11 @@ dependencies = [ [[package]] name = "chumsky" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23170228b96236b5a7299057ac284a321457700bc8c41a4476052f0f4ba5349d" +checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9" dependencies = [ - "hashbrown 0.12.3", + "hashbrown 0.14.2", ] [[package]] @@ -793,6 +807,28 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "container-init" +version = "0.1.0" +dependencies = [ + "async-stream", + "color-eyre", + "futures", + "helpers", + "imbl", + "nix 0.27.1", + "procfs", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tracing", + "tracing-error", + "tracing-futures", + "tracing-subscriber", + "yajrc 0.1.0 (git+https://github.com/dr-bonez/yajrc.git?branch=develop)", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -892,9 +928,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -910,9 +946,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" @@ -960,9 +996,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +checksum = "28f85c3514d2a6e64160359b45a3918c3b4178bcbf4ae5d03ab2d02e521c479a" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -1058,13 +1094,13 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1088,7 +1124,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1099,7 +1135,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1109,7 +1145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if 1.0.0", - "hashbrown 0.14.1", + "hashbrown 0.14.2", "lock_api", "once_cell", "parking_lot_core", @@ -1145,7 +1181,7 @@ checksum = "3c65c2ffdafc1564565200967edc4851c7b55422d3913466688907efd05ea26f" dependencies = [ "deno-proc-macro-rules-macros", "proc-macro2", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1157,7 +1193,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1207,7 +1243,7 @@ dependencies = [ "deno_ops", "deno_unsync", "futures", - "indexmap 2.0.2", + "indexmap 2.1.0", "libc", "log", "once_cell", @@ -1217,7 +1253,7 @@ dependencies = [ "serde_json", "serde_v8", "smallvec", - "sourcemap 7.0.0", + "sourcemap 7.0.1", "tokio", "url", "v8", @@ -1244,13 +1280,13 @@ dependencies = [ "lazy-regex", "once_cell", "pmutil", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "regex", "strum", "strum_macros", - "syn 2.0.38", + "syn 2.0.39", "thiserror", ] @@ -1384,9 +1420,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" [[package]] name = "ecdsa" @@ -1480,28 +1516,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "embassy_container_init" -version = "0.1.0" -dependencies = [ - "async-stream", - "color-eyre", - "futures", - "helpers", - "imbl", - "nix 0.27.1", - "procfs", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tracing", - "tracing-error", - "tracing-futures", - "tracing-subscriber", - "yajrc 0.1.0 (git+https://github.com/dr-bonez/yajrc.git?branch=develop)", -] - [[package]] name = "emver" version = "0.1.7" @@ -1552,7 +1566,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1570,9 +1584,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime 2.1.0", "is-terminal", @@ -1589,9 +1603,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" dependencies = [ "libc", "windows-sys 0.48.0", @@ -1651,9 +1665,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +checksum = "f69037fe1b785e84986b4f2cbcf647381876a00671d25ceef715d7812dd7e1dd" [[package]] name = "filetime" @@ -1748,7 +1762,7 @@ dependencies = [ "pmutil", "proc-macro2", "swc_macros_common", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1769,9 +1783,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -1784,9 +1798,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -1794,15 +1808,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -1822,38 +1836,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -1891,9 +1905,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if 1.0.0", "libc", @@ -1965,9 +1979,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.6", -] [[package]] name = "hashbrown" @@ -1975,16 +1986,16 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", ] [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "allocator-api2", ] @@ -1994,14 +2005,14 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.1", + "hashbrown 0.14.2", ] [[package]] name = "hdrhistogram" -version = "7.5.2" +version = "7.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f19b9f54f7c7f55e31401bb647626ce0cf0f67b0004982ce815b3ee72a02aa8" +checksum = "a5b38e5c02b7c7be48c8dc5217c4f1634af2ea221caae2e024bffc7a7651c691" dependencies = [ "base64 0.13.1", "byteorder", @@ -2103,9 +2114,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -2167,7 +2178,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -2206,8 +2217,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbfe4981e45b0a7403a55d4af12f8d30e173e722409658c3857243990e72180" dependencies = [ "anyhow", - "base64 0.21.4", - "env_logger 0.10.0", + "base64 0.21.5", + "env_logger 0.10.1", "futures", "hyper", "log", @@ -2293,9 +2304,9 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "imbl" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b4555023847ca2cd6fd11f20b553886e6981c7e8aee9b3e7e960b4b17fb440" +checksum = "978d142c8028edf52095703af2fad11d6f611af1246685725d6b850634647085" dependencies = [ "bitmaps", "imbl-sized-chunks", @@ -2364,12 +2375,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.2", "serde", ] @@ -2405,6 +2416,16 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "integer-encoding" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924df4f0e24e2e7f9cdd90babb0b96f93b20f3ecfa949ea9e6613756b8c8e1bf" +dependencies = [ + "async-trait", + "tokio", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -2418,9 +2439,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" dependencies = [ "serde", ] @@ -2445,7 +2466,7 @@ dependencies = [ "pmutil", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2455,7 +2476,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.3", - "rustix 0.38.19", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -2508,7 +2529,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb52eeac20f256459e909bd4a03bb8c4fab6a1fdbb8ed52d00f644152df48ece" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.7", "dyn-clone", "hifijson", "indexmap 1.9.3", @@ -2547,7 +2568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5754487a088f527b1407df470db8e654e4064dccbbe1fe850e0773721e9962b7" dependencies = [ "anyhow", - "base64 0.21.4", + "base64 0.21.5", "flate2", "once_cell", "openssl", @@ -2559,23 +2580,14 @@ dependencies = [ ] [[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "js_engine" +name = "js-engine" version = "0.1.0" dependencies = [ "async-trait", + "container-init", "dashmap", "deno_ast", "deno_core", - "embassy_container_init", "helpers", "itertools 0.11.0", "lazy_static", @@ -2589,6 +2601,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "js-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "json-patch" version = "0.2.7-alpha.0" @@ -2662,9 +2683,9 @@ dependencies = [ [[package]] name = "lazy-regex" -version = "3.0.2" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e723bd417b2df60a0f6a2b6825f297ea04b245d4ba52b5a22cb679bdf58b05fa" +checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c" dependencies = [ "lazy-regex-proc_macros", "once_cell", @@ -2673,14 +2694,14 @@ dependencies = [ [[package]] name = "lazy-regex-proc_macros" -version = "3.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0a1d9139f0ee2e862e08a9c5d0ba0470f2aa21cd1e1aa1b1562f83116c725f" +checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b" dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2710,9 +2731,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libloading" @@ -2730,6 +2751,17 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "libsqlite3-sys" version = "0.26.0" @@ -2749,9 +2781,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "lock_api" @@ -2860,9 +2892,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -2873,7 +2905,7 @@ dependencies = [ name = "models" version = "0.1.0" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "color-eyre", "ed25519-dalek 2.0.0", "emver", @@ -3105,23 +3137,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb" +checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597" +checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3157,7 +3189,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c75a0ec2d1b302412fb503224289325fcc0e44600176864804c7211b055cfd58" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "byteorder", "md-5", "sha2 0.10.8", @@ -3166,9 +3198,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" dependencies = [ "bitflags 2.4.1", "cfg-if 1.0.0", @@ -3187,7 +3219,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3198,18 +3230,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.1.5+3.1.3" +version = "300.1.6+3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559068e4c12950d7dcaa1857a61725c0d38d4fc03ff8e070ab31a75d6e316491" +checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" dependencies = [ "cc", "libc", @@ -3374,7 +3406,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.2", + "indexmap 2.1.0", ] [[package]] @@ -3438,7 +3470,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3482,9 +3514,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.1.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" [[package]] name = "pmutil" @@ -3494,14 +3526,14 @@ checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "portable-atomic" -version = "1.4.3" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" +checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" [[package]] name = "powerfmt" @@ -3537,9 +3569,9 @@ dependencies = [ [[package]] name = "primeorder" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3" +checksum = "c7dbe9ed3b56368bd99483eb32fe9c17fdd3730aebadc906918ce78d54c7eeb4" dependencies = [ "elliptic-curve", ] @@ -3554,6 +3586,15 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -3581,14 +3622,14 @@ dependencies = [ "flate2", "hex", "lazy_static", - "rustix 0.36.16", + "rustix 0.36.17", ] [[package]] name = "proptest" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", "bit-vec", @@ -3598,7 +3639,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.7.5", + "regex-syntax 0.8.2", "rusty-fork", "tempfile", "unarray", @@ -3635,7 +3676,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3752,7 +3793,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", ] [[package]] @@ -3817,12 +3858,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.10", - "redox_syscall 0.2.16", + "getrandom 0.2.11", + "libredox", "thiserror", ] @@ -3864,12 +3905,6 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - [[package]] name = "regex-syntax" version = "0.8.2" @@ -3882,7 +3917,7 @@ version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "cookie 0.16.2", "cookie_store 0.16.2", @@ -3943,28 +3978,27 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" dependencies = [ "cc", + "getrandom 0.2.11", "libc", - "once_cell", - "spin 0.5.2", + "spin 0.9.8", "untrusted", - "web-sys", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rpassword" -version = "7.2.0" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -4013,16 +4047,14 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +checksum = "86ef35bf3e7fe15a53c4ab08a998e42271eab13eb0db224126bc7bc4c4bad96d" dependencies = [ - "byteorder", "const-oid", "digest 0.10.7", "num-bigint-dig", "num-integer", - "num-iter", "num-traits", "pkcs1", "pkcs8", @@ -4036,12 +4068,12 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -4050,7 +4082,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e71971821b3ae0e769e4a4328dbcb517607b434db7697e9aba17203ec14e46a" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "blake2b_simd", "constant_time_eq", ] @@ -4087,9 +4119,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.16" +version = "0.36.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6da3636faa25820d8648e0e31c5d519bbb01f72fdf57131f0f5f7da5fed36eab" +checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" dependencies = [ "bitflags 1.3.2", "errno", @@ -4101,22 +4133,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.19" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.10", + "linux-raw-sys 0.4.11", "windows-sys 0.48.0", ] [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", "ring", @@ -4126,18 +4158,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", ] [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", @@ -4190,9 +4222,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", @@ -4258,9 +4290,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] @@ -4303,22 +4335,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "itoa", "ryu", "serde", @@ -4326,9 +4358,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -4367,11 +4399,11 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_json", "serde_with_macros", @@ -4387,16 +4419,16 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "serde_yaml" -version = "0.9.25" +version = "0.9.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "itoa", "ryu", "serde", @@ -4529,9 +4561,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "smartstring" @@ -4544,11 +4576,20 @@ dependencies = [ "version_check", ] +[[package]] +name = "snapshot_creator" +version = "0.1.0" +dependencies = [ + "dashmap", + "deno_ast", + "deno_core", +] + [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -4556,9 +4597,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys 0.48.0", @@ -4582,9 +4623,9 @@ dependencies = [ [[package]] name = "sourcemap" -version = "7.0.0" +version = "7.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbecc42a2b6131acc3bf9a25c9fe4161dba438eb52131bba83c5d781b5b70be3" +checksum = "10da010a590ed2fa9ca8467b00ce7e9c5a8017742c0c09c45450efc172208c4b" dependencies = [ "data-encoding", "debugid", @@ -4651,7 +4692,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "atoi", "byteorder", "bytes", @@ -4668,7 +4709,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.0.2", + "indexmap 2.1.0", "log", "memchr", "once_cell", @@ -4735,7 +4776,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db" dependencies = [ "atoi", - "base64 0.21.4", + "base64 0.21.5", "bitflags 2.4.1", "byteorder", "bytes", @@ -4778,7 +4819,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624" dependencies = [ "atoi", - "base64 0.21.4", + "base64 0.21.5", "bitflags 2.4.1", "byteorder", "chrono", @@ -4857,7 +4898,7 @@ dependencies = [ "quote", "regex-syntax 0.6.29", "strsim 0.10.0", - "syn 2.0.38", + "syn 2.0.39", "unicode-width", ] @@ -4931,10 +4972,11 @@ dependencies = [ "async-trait", "avahi-sys", "base32", - "base64 0.21.4", + "base64 0.21.5", "base64ct", "basic-cookies", "bimap", + "blake3", "bytes", "chrono", "ciborium", @@ -4942,6 +4984,7 @@ dependencies = [ "color-eyre", "console", "console-subscriber", + "container-init", "cookie 0.18.0", "cookie_store 0.20.0", "current_platform", @@ -4950,7 +4993,6 @@ dependencies = [ "ed25519 2.2.3", "ed25519-dalek 1.0.1", "ed25519-dalek 2.0.0", - "embassy_container_init", "emver", "fd-lock-rs", "futures", @@ -4965,8 +5007,9 @@ dependencies = [ "imbl", "imbl-value", "include_dir", - "indexmap 2.0.2", + "indexmap 2.1.0", "indicatif", + "integer-encoding", "ipnet", "iprange", "isocountry", @@ -4974,7 +5017,7 @@ dependencies = [ "jaq-core", "jaq-std", "josekit", - "js_engine", + "js-engine", "jsonpath_lib", "lazy_static", "libc", @@ -5023,7 +5066,7 @@ dependencies = [ "tokio-tar", "tokio-tungstenite", "tokio-util", - "toml 0.8.2", + "toml 0.8.8", "torut", "tracing", "tracing-error", @@ -5093,7 +5136,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5138,7 +5181,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5210,7 +5253,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5259,7 +5302,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5342,7 +5385,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5446,7 +5489,7 @@ dependencies = [ "pmutil", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5458,7 +5501,7 @@ dependencies = [ "pmutil", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5482,7 +5525,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5498,9 +5541,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -5553,14 +5596,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if 1.0.0", "fastrand", - "redox_syscall 0.3.5", - "rustix 0.38.19", + "redox_syscall 0.4.1", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -5610,22 +5653,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5704,9 +5747,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -5716,7 +5759,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.4", + "socket2 0.5.5", "tokio-macros", "tracing", "windows-sys 0.48.0", @@ -5734,13 +5777,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5817,9 +5860,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -5843,21 +5886,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.21.0", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -5868,7 +5911,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -5877,11 +5920,22 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -5897,7 +5951,7 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64 0.21.4", + "base64 0.21.5", "bytes", "h2", "http", @@ -5969,9 +6023,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", @@ -5987,7 +6041,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -6033,20 +6087,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -6081,9 +6135,9 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559ac980345f7f5020883dd3bcacf176355225e01916f8c2efecad7534f682c6" +checksum = "3119112651c157f4488931a01e586aa459736e9d6046d3bd9105ffb69352d374" dependencies = [ "async-trait", "cfg-if 1.0.0", @@ -6106,9 +6160,9 @@ dependencies = [ [[package]] name = "trust-dns-server" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4307166910ddf09378e651e9d4730c44900e9e0e1f157a6b955e48b539cd1d6" +checksum = "c540f73c2b2ec2f6c54eabd0900e7aafb747a820224b742f556e8faabb461bc7" dependencies = [ "async-trait", "bytes", @@ -6175,7 +6229,7 @@ checksum = "8fa054ee5e2346187d631d2f1d1fd3b33676772d6d03a2d84e1c5213b31674ee" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -6258,9 +6312,9 @@ checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" @@ -6292,7 +6346,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", ] [[package]] @@ -6363,9 +6417,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -6373,24 +6427,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -6400,9 +6454,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6410,22 +6464,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "wasm-streams" @@ -6442,9 +6496,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -6477,7 +6531,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.19", + "rustix 0.38.21", ] [[package]] @@ -6660,9 +6714,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.17" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] @@ -6733,12 +6787,32 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f355ab62ebe30b758c1f4ab096a306722c4b7dbfb9d8c07d18c70d71a945588" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "hashbrown 0.13.2", "lazy_static", "serde", ] +[[package]] +name = "zerocopy" +version = "0.7.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "zeroize" version = "1.6.0" @@ -6756,5 +6830,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100644 index 000000000..894362522 --- /dev/null +++ b/core/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] + +members = [ + "container-init", + "helpers", + "js-engine", + "models", + "snapshot-creator", + "startos", +] diff --git a/core/README.md b/core/README.md new file mode 100644 index 000000000..7a4be62a1 --- /dev/null +++ b/core/README.md @@ -0,0 +1,35 @@ +# StartOS Backend + +- Requirements: + - [Install Rust](https://rustup.rs) + - Recommended: [rust-analyzer](https://rust-analyzer.github.io/) + - [Docker](https://docs.docker.com/get-docker/) + +## Structure + +- `startos`: This contains the core library for StartOS that supports building `startbox`. +- `container-init` (ignore: deprecated) +- `js-engine`: This contains the library required to build `deno` to support running `.js` maintainer scripts for v0.3 +- `snapshot-creator`: This contains a binary used to build `v8` runtime snapshots, required for initializing `start-deno` +- `helpers`: This contains utility functions used across both `startos` and `js-engine` +- `models`: This contains types that are shared across `startos`, `js-engine`, and `helpers` + +## Artifacts + +The StartOS backend is packed into a single binary `startbox` that is symlinked under +several different names for different behaviour: + +- `startd`: This is the main daemon of StartOS +- `start-cli`: This is a CLI tool that will allow you to issue commands to + `startd` and control it similarly to the UI +- `start-sdk`: This is a CLI tool that aids in building and packaging services + you wish to deploy to StartOS +- `start-deno`: This is a CLI tool invoked by startd to run `.js` maintainer scripts for v0.3 +- `avahi-alias`: This is a CLI tool invoked by startd to create aliases in `avahi` for mDNS + +## Questions + +If you have questions about how various pieces of the backend system work. Open +an issue and tag the following people + +- dr-bonez diff --git a/backend/build-prod.sh b/core/build-prod.sh similarity index 65% rename from backend/build-prod.sh rename to core/build-prod.sh index d6c64eec2..214429727 100755 --- a/backend/build-prod.sh +++ b/core/build-prod.sh @@ -1,5 +1,7 @@ #!/bin/bash +cd "$(dirname "${BASH_SOURCE[0]}")" + set -e shopt -s expand_aliases @@ -7,11 +9,6 @@ if [ -z "$ARCH" ]; then ARCH=$(uname -m) fi -if [ "$0" != "./build-prod.sh" ]; then - >&2 echo "Must be run from backend directory" - exit 1 -fi - USE_TTY= if tty -s; then USE_TTY="-it" @@ -28,23 +25,20 @@ set +e fail= echo "FEATURES=\"$FEATURES\"" echo "RUSTFLAGS=\"$RUSTFLAGS\"" -rust-gnu-builder sh -c "(cd backend && cargo build --release --features avahi-alias,$FEATURES --locked --target=$ARCH-unknown-linux-gnu)" -if test $? -ne 0; then +if ! rust-gnu-builder sh -c "(cd core && cargo build --release --features avahi-alias,$FEATURES --locked --bin startbox --target=$ARCH-unknown-linux-gnu)"; then fail=true fi for ARCH in x86_64 aarch64 do - rust-musl-builder sh -c "(cd libs && cargo build --release --locked --bin embassy_container_init)" - if test $? -ne 0; then + if ! rust-musl-builder sh -c "(cd core && cargo build --release --locked --bin container-init)"; then fail=true fi done set -e -cd backend +cd core sudo chown -R $USER target sudo chown -R $USER ~/.cargo -sudo chown -R $USER ../libs/target if [ -n "$fail" ]; then exit 1 diff --git a/libs/build-arm-v8-snapshot.sh b/core/build-v8-snapshot.sh similarity index 57% rename from libs/build-arm-v8-snapshot.sh rename to core/build-v8-snapshot.sh index 4c11adfb4..58ff27c79 100755 --- a/libs/build-arm-v8-snapshot.sh +++ b/core/build-v8-snapshot.sh @@ -1,12 +1,14 @@ #!/bin/bash # Reason for this being is that we need to create a snapshot for the deno runtime. It wants to pull 3 files from build, and during the creation it gets embedded, but for some # reason during the actual runtime it is looking for them. So this will create a docker in arm that creates the snaphot needed for the arm + +cd "$(dirname "${BASH_SOURCE[0]}")" + set -e shopt -s expand_aliases -if [ "$0" != "./build-arm-v8-snapshot.sh" ]; then - >&2 echo "Must be run from backend/workspace directory" - exit 1 +if [ -z "$ARCH" ]; then + ARCH=$(uname -m) fi USE_TTY= @@ -18,14 +20,20 @@ alias 'rust-gnu-builder'='docker run $USE_TTY --rm -v "$HOME/.cargo/registry":/u echo "Building " cd .. -rust-gnu-builder sh -c "(cd libs/ && cargo build -p snapshot_creator --release --target=aarch64-unknown-linux-gnu)" +rust-gnu-builder sh -c "(cd core/ && cargo build -p snapshot_creator --release --target=${ARCH}-unknown-linux-gnu)" cd - +if [ "$ARCH" = "aarch64" ]; then + DOCKER_ARCH='arm64/v8' +elif [ "$ARCH" = "x86_64" ]; then + DOCKER_ARCH='amd64' +fi + echo "Creating Arm v8 Snapshot" -docker run $USE_TTY --platform linux/arm64/v8 --mount type=bind,src=$(pwd),dst=/mnt arm64v8/ubuntu:22.04 /bin/sh -c "cd /mnt && /mnt/target/aarch64-unknown-linux-gnu/release/snapshot_creator" +docker run $USE_TTY --platform "linux/${DOCKER_ARCH}" --mount type=bind,src=$(pwd),dst=/mnt ubuntu:22.04 /bin/sh -c "cd /mnt && /mnt/target/${ARCH}-unknown-linux-gnu/release/snapshot_creator" sudo chown -R $USER target sudo chown -R $USER ~/.cargo sudo chown $USER JS_SNAPSHOT.bin sudo chmod 0644 JS_SNAPSHOT.bin -sudo mv -f JS_SNAPSHOT.bin ./js_engine/src/artifacts/ARM_JS_SNAPSHOT.bin \ No newline at end of file +sudo mv -f JS_SNAPSHOT.bin ./js-engine/src/artifacts/JS_SNAPSHOT.${ARCH}.bin \ No newline at end of file diff --git a/libs/embassy_container_init/Cargo.toml b/core/container-init/Cargo.toml similarity index 96% rename from libs/embassy_container_init/Cargo.toml rename to core/container-init/Cargo.toml index c7da951f7..8229973d7 100644 --- a/libs/embassy_container_init/Cargo.toml +++ b/core/container-init/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "embassy_container_init" +name = "container-init" version = "0.1.0" edition = "2021" rust = "1.66" diff --git a/libs/embassy_container_init/src/lib.rs b/core/container-init/src/lib.rs similarity index 100% rename from libs/embassy_container_init/src/lib.rs rename to core/container-init/src/lib.rs diff --git a/libs/embassy_container_init/src/main.rs b/core/container-init/src/main.rs similarity index 99% rename from libs/embassy_container_init/src/main.rs rename to core/container-init/src/main.rs index 7ac72ca77..997537808 100644 --- a/libs/embassy_container_init/src/main.rs +++ b/core/container-init/src/main.rs @@ -4,7 +4,7 @@ use std::os::unix::process::ExitStatusExt; use std::process::Stdio; use std::sync::Arc; -use embassy_container_init::{ +use container_init::{ LogParams, OutputParams, OutputStrategy, ProcessGroupId, ProcessId, RunCommandParams, SendSignalParams, SignalGroupParams, }; @@ -335,7 +335,7 @@ async fn main() { use tracing_subscriber::prelude::*; use tracing_subscriber::{fmt, EnvFilter}; - let filter_layer = EnvFilter::new("embassy_container_init=debug"); + let filter_layer = EnvFilter::new("container_init=debug"); let fmt_layer = fmt::layer().with_target(true); tracing_subscriber::registry() diff --git a/libs/helpers/Cargo.toml b/core/helpers/Cargo.toml similarity index 100% rename from libs/helpers/Cargo.toml rename to core/helpers/Cargo.toml diff --git a/libs/helpers/src/byte_replacement_reader.rs b/core/helpers/src/byte_replacement_reader.rs similarity index 100% rename from libs/helpers/src/byte_replacement_reader.rs rename to core/helpers/src/byte_replacement_reader.rs diff --git a/libs/helpers/src/lib.rs b/core/helpers/src/lib.rs similarity index 100% rename from libs/helpers/src/lib.rs rename to core/helpers/src/lib.rs diff --git a/libs/helpers/src/os_api.rs b/core/helpers/src/os_api.rs similarity index 100% rename from libs/helpers/src/os_api.rs rename to core/helpers/src/os_api.rs diff --git a/libs/helpers/src/rpc_client.rs b/core/helpers/src/rpc_client.rs similarity index 100% rename from libs/helpers/src/rpc_client.rs rename to core/helpers/src/rpc_client.rs diff --git a/libs/helpers/src/rsync.rs b/core/helpers/src/rsync.rs similarity index 100% rename from libs/helpers/src/rsync.rs rename to core/helpers/src/rsync.rs diff --git a/libs/helpers/src/script_dir.rs b/core/helpers/src/script_dir.rs similarity index 100% rename from libs/helpers/src/script_dir.rs rename to core/helpers/src/script_dir.rs diff --git a/core/install-sdk.sh b/core/install-sdk.sh new file mode 100755 index 000000000..3eec40012 --- /dev/null +++ b/core/install-sdk.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +cd "$(dirname "${BASH_SOURCE[0]}")" + +set -e +shopt -s expand_aliases + +web="../web/dist/static" +[ -d "$web" ] || mkdir -p "$web" + +if [ -z "$PLATFORM" ]; then + export PLATFORM=$(uname -m) +fi + +cargo install --path=./startos --no-default-features --features=js_engine,sdk,cli --locked +startbox_loc=$(which startbox) +ln -sf $startbox_loc $(dirname $startbox_loc)/start-cli +ln -sf $startbox_loc $(dirname $startbox_loc)/start-sdk diff --git a/libs/js_engine/Cargo.toml b/core/js-engine/Cargo.toml similarity index 87% rename from libs/js_engine/Cargo.toml rename to core/js-engine/Cargo.toml index cdff104f0..3d1f0743d 100644 --- a/libs/js_engine/Cargo.toml +++ b/core/js-engine/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "js_engine" +name = "js-engine" version = "0.1.0" edition = "2021" @@ -10,7 +10,7 @@ async-trait = "0.1.74" dashmap = "5.5.3" deno_core = "=0.222.0" deno_ast = { version = "=0.29.5", features = ["transpiling"] } -embassy_container_init = { path = "../embassy_container_init" } +container-init = { path = "../container-init" } reqwest = { version = "0.11.22" } sha2 = "0.10.8" itertools = "0.11.0" diff --git a/libs/js_engine/src/artifacts/ARM_JS_SNAPSHOT.bin b/core/js-engine/src/artifacts/JS_SNAPSHOT.aarch64.bin similarity index 100% rename from libs/js_engine/src/artifacts/ARM_JS_SNAPSHOT.bin rename to core/js-engine/src/artifacts/JS_SNAPSHOT.aarch64.bin diff --git a/libs/js_engine/src/artifacts/JS_SNAPSHOT.bin b/core/js-engine/src/artifacts/JS_SNAPSHOT.x86_64.bin similarity index 100% rename from libs/js_engine/src/artifacts/JS_SNAPSHOT.bin rename to core/js-engine/src/artifacts/JS_SNAPSHOT.x86_64.bin diff --git a/libs/js_engine/src/artifacts/loadModule.js b/core/js-engine/src/artifacts/loadModule.js similarity index 100% rename from libs/js_engine/src/artifacts/loadModule.js rename to core/js-engine/src/artifacts/loadModule.js diff --git a/libs/js_engine/src/lib.rs b/core/js-engine/src/lib.rs similarity index 99% rename from libs/js_engine/src/lib.rs rename to core/js-engine/src/lib.rs index 514560077..edb5b9b59 100644 --- a/libs/js_engine/src/lib.rs +++ b/core/js-engine/src/lib.rs @@ -88,10 +88,10 @@ pub struct MetadataJs { } #[cfg(target_arch = "x86_64")] -const SNAPSHOT_BYTES: &[u8] = include_bytes!("./artifacts/JS_SNAPSHOT.bin"); +const SNAPSHOT_BYTES: &[u8] = include_bytes!("./artifacts/JS_SNAPSHOT.x86_64.bin"); #[cfg(target_arch = "aarch64")] -const SNAPSHOT_BYTES: &[u8] = include_bytes!("./artifacts/ARM_JS_SNAPSHOT.bin"); +const SNAPSHOT_BYTES: &[u8] = include_bytes!("./artifacts/JS_SNAPSHOT.aarch64.bin"); #[derive(Clone)] struct JsContext { @@ -426,10 +426,10 @@ mod fns { use std::rc::Rc; use std::time::Duration; + use container_init::ProcessId; use deno_core::anyhow::{anyhow, bail}; use deno_core::error::AnyError; use deno_core::*; - use embassy_container_init::ProcessId; use helpers::{to_tmp_path, AtomicFile, Rsync, RsyncOptions}; use itertools::Itertools; use models::{PackageId, VolumeId}; @@ -1468,11 +1468,11 @@ mod fns { #[tokio::test] async fn test_is_subset() { - assert!( - !is_subset("/home/drbonez", "/home/drbonez/code/fakedir/../../..") - .await - .unwrap() - ) + let home = std::env::var("HOME").unwrap(); + let home = Path::new(&home); + assert!(!is_subset(home, &home.join("code/fakedir/../../..")) + .await + .unwrap()) } } diff --git a/libs/models/Cargo.toml b/core/models/Cargo.toml similarity index 100% rename from libs/models/Cargo.toml rename to core/models/Cargo.toml diff --git a/libs/models/src/data_url.rs b/core/models/src/data_url.rs similarity index 100% rename from libs/models/src/data_url.rs rename to core/models/src/data_url.rs diff --git a/libs/models/src/errors.rs b/core/models/src/errors.rs similarity index 100% rename from libs/models/src/errors.rs rename to core/models/src/errors.rs diff --git a/libs/models/src/id/action.rs b/core/models/src/id/action.rs similarity index 100% rename from libs/models/src/id/action.rs rename to core/models/src/id/action.rs diff --git a/libs/models/src/id/address.rs b/core/models/src/id/address.rs similarity index 100% rename from libs/models/src/id/address.rs rename to core/models/src/id/address.rs diff --git a/libs/models/src/id/health_check.rs b/core/models/src/id/health_check.rs similarity index 100% rename from libs/models/src/id/health_check.rs rename to core/models/src/id/health_check.rs diff --git a/libs/models/src/id/image.rs b/core/models/src/id/image.rs similarity index 100% rename from libs/models/src/id/image.rs rename to core/models/src/id/image.rs diff --git a/libs/models/src/id/interface.rs b/core/models/src/id/interface.rs similarity index 100% rename from libs/models/src/id/interface.rs rename to core/models/src/id/interface.rs diff --git a/libs/models/src/id/invalid_id.rs b/core/models/src/id/invalid_id.rs similarity index 100% rename from libs/models/src/id/invalid_id.rs rename to core/models/src/id/invalid_id.rs diff --git a/libs/models/src/id/mod.rs b/core/models/src/id/mod.rs similarity index 100% rename from libs/models/src/id/mod.rs rename to core/models/src/id/mod.rs diff --git a/libs/models/src/id/package.rs b/core/models/src/id/package.rs similarity index 100% rename from libs/models/src/id/package.rs rename to core/models/src/id/package.rs diff --git a/libs/models/src/id/volume.rs b/core/models/src/id/volume.rs similarity index 100% rename from libs/models/src/id/volume.rs rename to core/models/src/id/volume.rs diff --git a/libs/models/src/js_engine_types.rs b/core/models/src/js_engine_types.rs similarity index 93% rename from libs/models/src/js_engine_types.rs rename to core/models/src/js_engine_types.rs index ab3b44c06..3722d8c76 100644 --- a/libs/models/src/js_engine_types.rs +++ b/core/models/src/js_engine_types.rs @@ -1,18 +1,19 @@ -use std::{future::Future, pin::Pin, sync::Arc, time::Duration}; +use std::future::Future; +use std::pin::Pin; +use std::sync::Arc; +use std::time::Duration; use color_eyre::eyre::bail; -use embassy_container_init::{Input, Output, ProcessId, RpcId}; -use tokio::sync::{ - mpsc::{UnboundedReceiver, UnboundedSender}, - Mutex, -}; +use container_init::{Input, Output, ProcessId, RpcId}; +use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; +use tokio::sync::Mutex; /// Used by the js-executor, it is the ability to just create a command in an already running exec pub type ExecCommand = Arc< dyn Fn( String, Vec, - UnboundedSender, + UnboundedSender, Option, ) -> Pin> + 'static>> + Send @@ -33,7 +34,7 @@ pub trait CommandInserter { &self, command: String, args: Vec, - sender: UnboundedSender, + sender: UnboundedSender, timeout: Option, ) -> Pin>>>; diff --git a/libs/models/src/lib.rs b/core/models/src/lib.rs similarity index 100% rename from libs/models/src/lib.rs rename to core/models/src/lib.rs diff --git a/libs/models/src/mime.rs b/core/models/src/mime.rs similarity index 100% rename from libs/models/src/mime.rs rename to core/models/src/mime.rs diff --git a/libs/models/src/procedure_name.rs b/core/models/src/procedure_name.rs similarity index 100% rename from libs/models/src/procedure_name.rs rename to core/models/src/procedure_name.rs diff --git a/libs/models/src/version.rs b/core/models/src/version.rs similarity index 100% rename from libs/models/src/version.rs rename to core/models/src/version.rs diff --git a/backend/rustfmt.toml b/core/rustfmt.toml similarity index 100% rename from backend/rustfmt.toml rename to core/rustfmt.toml diff --git a/libs/snapshot_creator/Cargo.toml b/core/snapshot-creator/Cargo.toml similarity index 100% rename from libs/snapshot_creator/Cargo.toml rename to core/snapshot-creator/Cargo.toml diff --git a/libs/snapshot_creator/src/main.rs b/core/snapshot-creator/src/main.rs similarity index 100% rename from libs/snapshot_creator/src/main.rs rename to core/snapshot-creator/src/main.rs diff --git a/core/src/s9pk/merkle_archive/directory_contents.rs b/core/src/s9pk/merkle_archive/directory_contents.rs new file mode 100644 index 000000000..f662300b6 --- /dev/null +++ b/core/src/s9pk/merkle_archive/directory_contents.rs @@ -0,0 +1,199 @@ +use std::collections::BTreeMap; +use std::path::Path; + +use futures::future::BoxFuture; +use futures::FutureExt; +use imbl_value::InternedString; +use tokio::io::AsyncRead; + +use crate::prelude::*; +use crate::s9pk::merkle_archive::hash::{Hash, HashWriter}; +use crate::s9pk::merkle_archive::sink::{Sink, TrackingWriter}; +use crate::s9pk::merkle_archive::source::{ArchiveSource, FileSource, Section}; +use crate::s9pk::merkle_archive::write_queue::WriteQueue; +use crate::s9pk::merkle_archive::{varint, Entry, EntryContents}; + +#[derive(Debug)] +pub struct DirectoryContents(BTreeMap>); +impl DirectoryContents { + pub fn new() -> Self { + Self(BTreeMap::new()) + } + + #[instrument(skip_all)] + pub fn get_path(&self, path: impl AsRef) -> Option<&Entry> { + let mut dir = Some(self); + let mut res = None; + for segment in path.as_ref().into_iter() { + let segment = segment.to_str()?; + if segment == "/" { + continue; + } + res = dir?.get(segment); + if let Some(EntryContents::Directory(d)) = res.as_ref().map(|e| e.as_contents()) { + dir = Some(d); + } else { + dir = None + } + } + res + } + + pub fn insert_path(&mut self, path: impl AsRef, entry: Entry) -> Result<(), Error> { + let path = path.as_ref(); + let (parent, Some(file)) = (path.parent(), path.file_name().and_then(|f| f.to_str())) + else { + return Err(Error::new( + eyre!("cannot create file at root"), + ErrorKind::Pack, + )); + }; + let mut dir = self; + for segment in parent.into_iter().flatten() { + let segment = segment + .to_str() + .ok_or_else(|| Error::new(eyre!("non-utf8 path segment"), ErrorKind::Utf8))?; + if segment == "/" { + continue; + } + if !dir.contains_key(segment) { + dir.insert( + segment.into(), + Entry::new(EntryContents::Directory(DirectoryContents::new())), + ); + } + if let Some(EntryContents::Directory(d)) = + dir.get_mut(segment).map(|e| e.as_contents_mut()) + { + dir = d; + } else { + return Err(Error::new(eyre!("failed to insert entry at path {path:?}: ancestor exists and is not a directory"), ErrorKind::Pack)); + } + } + dir.insert(file.into(), entry); + Ok(()) + } + + pub const fn header_size() -> u64 { + 8 // position: u64 BE + + 8 // size: u64 BE + } + + #[instrument(skip_all)] + pub async fn serialize_header(&self, position: u64, w: &mut W) -> Result { + use tokio::io::AsyncWriteExt; + + let size = self.toc_size(); + + w.write_all(&position.to_be_bytes()).await?; + w.write_all(&size.to_be_bytes()).await?; + + Ok(position) + } + + pub fn toc_size(&self) -> u64 { + self.0.iter().fold( + varint::serialized_varint_size(self.0.len() as u64), + |acc, (name, entry)| { + acc + varint::serialized_varstring_size(&**name) + entry.header_size() + }, + ) + } +} +impl DirectoryContents> { + #[instrument(skip_all)] + pub fn deserialize<'a>( + source: &'a S, + header: &'a mut (impl AsyncRead + Unpin + Send), + sighash: Hash, + ) -> BoxFuture<'a, Result> { + async move { + use tokio::io::AsyncReadExt; + + let mut position = [0u8; 8]; + header.read_exact(&mut position).await?; + let position = u64::from_be_bytes(position); + + let mut size = [0u8; 8]; + header.read_exact(&mut size).await?; + let size = u64::from_be_bytes(size); + + let mut toc_reader = source.fetch(position, size).await?; + + let len = varint::deserialize_varint(&mut toc_reader).await?; + let mut entries = BTreeMap::new(); + for _ in 0..len { + entries.insert( + varint::deserialize_varstring(&mut toc_reader).await?.into(), + Entry::deserialize(source, &mut toc_reader).await?, + ); + } + + let res = Self(entries); + + if res.sighash().await? == sighash { + Ok(res) + } else { + Err(Error::new( + eyre!("hash sum does not match"), + ErrorKind::InvalidSignature, + )) + } + } + .boxed() + } +} +impl DirectoryContents { + #[instrument(skip_all)] + pub fn update_hashes<'a>(&'a mut self, only_missing: bool) -> BoxFuture<'a, Result<(), Error>> { + async move { + for (_, entry) in &mut self.0 { + entry.update_hash(only_missing).await?; + } + Ok(()) + } + .boxed() + } + + #[instrument(skip_all)] + pub fn sighash<'a>(&'a self) -> BoxFuture<'a, Result> { + async move { + let mut hasher = TrackingWriter::new(0, HashWriter::new()); + let mut sig_contents = BTreeMap::new(); + for (name, entry) in &self.0 { + sig_contents.insert(name.clone(), entry.to_missing().await?); + } + Self(sig_contents) + .serialize_toc(&mut WriteQueue::new(0), &mut hasher) + .await?; + Ok(hasher.into_inner().finalize()) + } + .boxed() + } + + #[instrument(skip_all)] + pub async fn serialize_toc<'a, W: Sink>( + &'a self, + queue: &mut WriteQueue<'a, S>, + w: &mut W, + ) -> Result<(), Error> { + varint::serialize_varint(self.0.len() as u64, w).await?; + for (name, entry) in self.0.iter() { + varint::serialize_varstring(&**name, w).await?; + entry.serialize_header(queue.add(entry).await?, w).await?; + } + + Ok(()) + } +} +impl std::ops::Deref for DirectoryContents { + type Target = BTreeMap>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl std::ops::DerefMut for DirectoryContents { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} diff --git a/core/src/s9pk/merkle_archive/file_contents.rs b/core/src/s9pk/merkle_archive/file_contents.rs new file mode 100644 index 000000000..c02c0e879 --- /dev/null +++ b/core/src/s9pk/merkle_archive/file_contents.rs @@ -0,0 +1,82 @@ +use tokio::io::AsyncRead; + +use crate::prelude::*; +use crate::s9pk::merkle_archive::hash::{Hash, HashWriter}; +use crate::s9pk::merkle_archive::sink::{Sink, TrackingWriter}; +use crate::s9pk::merkle_archive::source::{ArchiveSource, FileSource, Section}; + +#[derive(Debug)] +pub struct FileContents(S); +impl FileContents { + pub fn new(source: S) -> Self { + Self(source) + } + pub const fn header_size() -> u64 { + 8 // position: u64 BE + + 8 // size: u64 BE + } +} +impl FileContents> { + #[instrument(skip_all)] + pub async fn deserialize( + source: &S, + header: &mut (impl AsyncRead + Unpin + Send), + ) -> Result { + use tokio::io::AsyncReadExt; + + let mut position = [0u8; 8]; + header.read_exact(&mut position).await?; + let position = u64::from_be_bytes(position); + + let mut size = [0u8; 8]; + header.read_exact(&mut size).await?; + let size = u64::from_be_bytes(size); + + Ok(Self(source.section(position, size))) + } +} +impl FileContents { + pub async fn hash(&self) -> Result { + let mut hasher = TrackingWriter::new(0, HashWriter::new()); + self.serialize_body(&mut hasher, None).await?; + Ok(hasher.into_inner().finalize()) + } + #[instrument(skip_all)] + pub async fn serialize_header(&self, position: u64, w: &mut W) -> Result { + use tokio::io::AsyncWriteExt; + + let size = self.0.size().await?; + + w.write_all(&position.to_be_bytes()).await?; + w.write_all(&size.to_be_bytes()).await?; + + Ok(position) + } + #[instrument(skip_all)] + pub async fn serialize_body( + &self, + w: &mut W, + verify: Option, + ) -> Result<(), Error> { + let start = if verify.is_some() { + Some(w.current_position().await?) + } else { + None + }; + self.0.copy_verify(w, verify).await?; + if let Some(start) = start { + ensure_code!( + w.current_position().await? - start == self.0.size().await?, + ErrorKind::Pack, + "FileSource::copy wrote a number of bytes that does not match FileSource::size" + ); + } + Ok(()) + } +} +impl std::ops::Deref for FileContents { + type Target = S; + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/core/src/s9pk/merkle_archive/hash.rs b/core/src/s9pk/merkle_archive/hash.rs new file mode 100644 index 000000000..ae2829012 --- /dev/null +++ b/core/src/s9pk/merkle_archive/hash.rs @@ -0,0 +1,97 @@ +pub use blake3::Hash; +use blake3::Hasher; +use tokio::io::AsyncWrite; + +use crate::prelude::*; + +#[pin_project::pin_project] +pub struct HashWriter { + hasher: Hasher, +} +impl HashWriter { + pub fn new() -> Self { + Self { + hasher: Hasher::new(), + } + } + pub fn finalize(self) -> Hash { + self.hasher.finalize() + } +} +impl AsyncWrite for HashWriter { + fn poll_write( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + self.project().hasher.update(buf); + std::task::Poll::Ready(Ok(buf.len())) + } + fn poll_flush( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(())) + } + fn poll_shutdown( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(())) + } +} + +#[pin_project::pin_project] +pub struct VerifyingWriter { + verify: Option<(Hasher, Hash)>, + #[pin] + writer: W, +} +impl VerifyingWriter { + pub fn new(w: W, verify: Option) -> Self { + Self { + verify: verify.map(|v| (Hasher::new(), v)), + writer: w, + } + } + pub fn verify(self) -> Result { + if let Some((actual, expected)) = self.verify { + ensure_code!( + actual.finalize() == expected, + ErrorKind::InvalidSignature, + "hash sum does not match" + ); + } + Ok(self.writer) + } +} +impl AsyncWrite for VerifyingWriter { + fn poll_write( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + let this = self.project(); + match this.writer.poll_write(cx, buf) { + std::task::Poll::Ready(Ok(written)) => { + if let Some((h, _)) = this.verify { + h.update(&buf[..written]); + } + std::task::Poll::Ready(Ok(written)) + } + a => a, + } + } + fn poll_flush( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.project().writer.poll_flush(cx) + } + fn poll_shutdown( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.project().writer.poll_shutdown(cx) + } +} diff --git a/core/src/s9pk/merkle_archive/mod.rs b/core/src/s9pk/merkle_archive/mod.rs new file mode 100644 index 000000000..f83cd2464 --- /dev/null +++ b/core/src/s9pk/merkle_archive/mod.rs @@ -0,0 +1,268 @@ +use ed25519_dalek::{Signature, SigningKey, VerifyingKey}; +use tokio::io::AsyncRead; + +use crate::prelude::*; +use crate::s9pk::merkle_archive::directory_contents::DirectoryContents; +use crate::s9pk::merkle_archive::file_contents::FileContents; +use crate::s9pk::merkle_archive::hash::Hash; +use crate::s9pk::merkle_archive::sink::Sink; +use crate::s9pk::merkle_archive::source::{ArchiveSource, FileSource, Section}; +use crate::s9pk::merkle_archive::write_queue::WriteQueue; + +pub mod directory_contents; +pub mod file_contents; +pub mod hash; +pub mod sink; +pub mod source; +#[cfg(test)] +mod test; +pub mod varint; +pub mod write_queue; + +#[derive(Debug)] +enum Signer { + Signed(VerifyingKey, Signature), + Signer(SigningKey), +} + +#[derive(Debug)] +pub struct MerkleArchive { + signer: Signer, + contents: DirectoryContents, +} +impl MerkleArchive { + pub fn new(contents: DirectoryContents, signer: SigningKey) -> Self { + Self { + signer: Signer::Signer(signer), + contents, + } + } + pub const fn header_size() -> u64 { + 32 // pubkey + + 64 // signature + + DirectoryContents::>::header_size() + } + pub fn contents(&self) -> &DirectoryContents { + &self.contents + } +} +impl MerkleArchive> { + #[instrument(skip_all)] + pub async fn deserialize( + source: &S, + header: &mut (impl AsyncRead + Unpin + Send), + ) -> Result { + use tokio::io::AsyncReadExt; + + let mut pubkey = [0u8; 32]; + header.read_exact(&mut pubkey).await?; + let pubkey = VerifyingKey::from_bytes(&pubkey)?; + + let mut signature = [0u8; 64]; + header.read_exact(&mut signature).await?; + let signature = Signature::from_bytes(&signature); + + let mut sighash = [0u8; 32]; + header.read_exact(&mut sighash).await?; + let sighash = Hash::from_bytes(sighash); + + let contents = DirectoryContents::deserialize(source, header, sighash).await?; + + pubkey.verify_strict(contents.sighash().await?.as_bytes(), &signature)?; + + Ok(Self { + signer: Signer::Signed(pubkey, signature), + contents, + }) + } +} +impl MerkleArchive { + pub async fn update_hashes(&mut self, only_missing: bool) -> Result<(), Error> { + self.contents.update_hashes(only_missing).await + } + #[instrument(skip_all)] + pub async fn serialize(&self, w: &mut W, verify: bool) -> Result<(), Error> { + use tokio::io::AsyncWriteExt; + + let sighash = self.contents.sighash().await?; + + let (pubkey, signature) = match &self.signer { + Signer::Signed(pubkey, signature) => (*pubkey, *signature), + Signer::Signer(s) => (s.into(), ed25519_dalek::Signer::sign(s, sighash.as_bytes())), + }; + + w.write_all(pubkey.as_bytes()).await?; + w.write_all(&signature.to_bytes()).await?; + w.write_all(sighash.as_bytes()).await?; + let mut next_pos = w.current_position().await?; + next_pos += DirectoryContents::::header_size(); + self.contents.serialize_header(next_pos, w).await?; + next_pos += self.contents.toc_size(); + let mut queue = WriteQueue::new(next_pos); + self.contents.serialize_toc(&mut queue, w).await?; + queue.serialize(w, verify).await?; + Ok(()) + } +} + +#[derive(Debug)] +pub struct Entry { + hash: Option, + contents: EntryContents, +} +impl Entry { + pub fn new(contents: EntryContents) -> Self { + Self { + hash: None, + contents, + } + } + pub fn hash(&self) -> Option { + self.hash + } + pub fn as_contents(&self) -> &EntryContents { + &self.contents + } + pub fn as_contents_mut(&mut self) -> &mut EntryContents { + self.hash = None; + &mut self.contents + } + pub fn into_contents(self) -> EntryContents { + self.contents + } + pub fn header_size(&self) -> u64 { + 32 // hash + + self.contents.header_size() + } +} +impl Entry> { + #[instrument(skip_all)] + pub async fn deserialize( + source: &S, + header: &mut (impl AsyncRead + Unpin + Send), + ) -> Result { + use tokio::io::AsyncReadExt; + + let mut hash = [0u8; 32]; + header.read_exact(&mut hash).await?; + let hash = Hash::from_bytes(hash); + + let contents = EntryContents::deserialize(source, header, hash).await?; + + Ok(Self { + hash: Some(hash), + contents, + }) + } +} +impl Entry { + pub async fn to_missing(&self) -> Result { + let hash = if let Some(hash) = self.hash { + hash + } else { + self.contents.hash().await? + }; + Ok(Self { + hash: Some(hash), + contents: EntryContents::Missing, + }) + } + pub async fn update_hash(&mut self, only_missing: bool) -> Result<(), Error> { + if let EntryContents::Directory(d) = &mut self.contents { + d.update_hashes(only_missing).await?; + } + self.hash = Some(self.contents.hash().await?); + Ok(()) + } + #[instrument(skip_all)] + pub async fn serialize_header( + &self, + position: u64, + w: &mut W, + ) -> Result, Error> { + use tokio::io::AsyncWriteExt; + + let hash = if let Some(hash) = self.hash { + hash + } else { + self.contents.hash().await? + }; + w.write_all(hash.as_bytes()).await?; + self.contents.serialize_header(position, w).await + } +} + +#[derive(Debug)] +pub enum EntryContents { + Missing, + File(FileContents), + Directory(DirectoryContents), +} +impl EntryContents { + fn type_id(&self) -> u8 { + match self { + Self::Missing => 0, + Self::File(_) => 1, + Self::Directory(_) => 2, + } + } + pub fn header_size(&self) -> u64 { + 1 // type + + match self { + Self::Missing => 0, + Self::File(_) => FileContents::::header_size(), + Self::Directory(_) => DirectoryContents::::header_size(), + } + } +} +impl EntryContents> { + #[instrument(skip_all)] + pub async fn deserialize( + source: &S, + header: &mut (impl AsyncRead + Unpin + Send), + hash: Hash, + ) -> Result { + use tokio::io::AsyncReadExt; + + let mut type_id = [0u8]; + header.read_exact(&mut type_id).await?; + match type_id[0] { + 0 => Ok(Self::Missing), + 1 => Ok(Self::File(FileContents::deserialize(source, header).await?)), + 2 => Ok(Self::Directory( + DirectoryContents::deserialize(source, header, hash).await?, + )), + id => Err(Error::new( + eyre!("Unknown type id {id} found in MerkleArchive"), + ErrorKind::ParseS9pk, + )), + } + } +} +impl EntryContents { + pub async fn hash(&self) -> Result { + match self { + Self::Missing => Err(Error::new( + eyre!("Cannot compute hash of missing file"), + ErrorKind::Pack, + )), + Self::File(f) => f.hash().await, + Self::Directory(d) => d.sighash().await, + } + } + #[instrument(skip_all)] + pub async fn serialize_header( + &self, + position: u64, + w: &mut W, + ) -> Result, Error> { + use tokio::io::AsyncWriteExt; + + w.write_all(&[self.type_id()]).await?; + Ok(match self { + Self::Missing => None, + Self::File(f) => Some(f.serialize_header(position, w).await?), + Self::Directory(d) => Some(d.serialize_header(position, w).await?), + }) + } +} diff --git a/core/src/s9pk/merkle_archive/sink.rs b/core/src/s9pk/merkle_archive/sink.rs new file mode 100644 index 000000000..c71377808 --- /dev/null +++ b/core/src/s9pk/merkle_archive/sink.rs @@ -0,0 +1,70 @@ +use tokio::io::{AsyncSeek, AsyncWrite}; + +use crate::prelude::*; + +#[async_trait::async_trait] +pub trait Sink: AsyncWrite + Unpin + Send { + async fn current_position(&mut self) -> Result; +} + +#[async_trait::async_trait] +impl Sink for S { + async fn current_position(&mut self) -> Result { + use tokio::io::AsyncSeekExt; + + Ok(self.stream_position().await?) + } +} + +#[async_trait::async_trait] +impl Sink for TrackingWriter { + async fn current_position(&mut self) -> Result { + Ok(self.position) + } +} + +#[pin_project::pin_project] +pub struct TrackingWriter { + position: u64, + #[pin] + writer: W, +} +impl TrackingWriter { + pub fn new(start: u64, w: W) -> Self { + Self { + position: start, + writer: w, + } + } + pub fn into_inner(self) -> W { + self.writer + } +} +impl AsyncWrite for TrackingWriter { + fn poll_write( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + let this = self.project(); + match this.writer.poll_write(cx, buf) { + std::task::Poll::Ready(Ok(written)) => { + *this.position += written as u64; + std::task::Poll::Ready(Ok(written)) + } + a => a, + } + } + fn poll_flush( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.project().writer.poll_flush(cx) + } + fn poll_shutdown( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.project().writer.poll_shutdown(cx) + } +} diff --git a/core/src/s9pk/merkle_archive/source/http.rs b/core/src/s9pk/merkle_archive/source/http.rs new file mode 100644 index 000000000..f38fd7028 --- /dev/null +++ b/core/src/s9pk/merkle_archive/source/http.rs @@ -0,0 +1,91 @@ +use std::sync::Arc; + +use bytes::Bytes; +use futures::stream::BoxStream; +use futures::{StreamExt, TryStreamExt}; +use http::header::{ACCEPT_RANGES, RANGE}; +use reqwest::{Client, Url}; +use tokio::io::AsyncRead; +use tokio::sync::Mutex; +use tokio_util::io::StreamReader; + +use crate::prelude::*; +use crate::s9pk::merkle_archive::source::ArchiveSource; + +#[derive(Clone)] +pub struct HttpSource { + url: Url, + client: Client, + range_support: Result< + (), + (), // Arc>> + >, +} +impl HttpSource { + pub async fn new(client: Client, url: Url) -> Result { + let range_support = client + .head(url.clone()) + .send() + .await + .with_kind(ErrorKind::Network)? + .error_for_status() + .with_kind(ErrorKind::Network)? + .headers() + .get(ACCEPT_RANGES) + .and_then(|s| s.to_str().ok()) + == Some("bytes"); + Ok(Self { + url, + client, + range_support: if range_support { + Ok(()) + } else { + todo!() // Err(Arc::new(Mutex::new(None))) + }, + }) + } +} +#[async_trait::async_trait] +impl ArchiveSource for HttpSource { + type Reader = HttpReader; + async fn fetch(&self, position: u64, size: u64) -> Result { + match self.range_support { + Ok(_) => Ok(HttpReader::Range(StreamReader::new(if size > 0 { + self.client + .get(self.url.clone()) + .header(RANGE, format!("bytes={}-{}", position, position + size - 1)) + .send() + .await + .with_kind(ErrorKind::Network)? + .error_for_status() + .with_kind(ErrorKind::Network)? + .bytes_stream() + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)) + .boxed() + } else { + futures::stream::empty().boxed() + }))), + _ => todo!(), + } + } +} + +#[pin_project::pin_project(project = HttpReaderProj)] +pub enum HttpReader { + Range(#[pin] StreamReader>, Bytes>), + // Rangeless(#[pin] RangelessReader), +} +impl AsyncRead for HttpReader { + fn poll_read( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> std::task::Poll> { + match self.project() { + HttpReaderProj::Range(r) => r.poll_read(cx, buf), + // HttpReaderProj::Rangeless(r) => r.poll_read(cx, buf), + } + } +} + +// type RangelessReader = StreamReader, Bytes>; diff --git a/core/src/s9pk/merkle_archive/source/mod.rs b/core/src/s9pk/merkle_archive/source/mod.rs new file mode 100644 index 000000000..3a7d60a40 --- /dev/null +++ b/core/src/s9pk/merkle_archive/source/mod.rs @@ -0,0 +1,120 @@ +use std::path::PathBuf; +use std::sync::Arc; + +use blake3::Hash; +use tokio::fs::File; +use tokio::io::{AsyncRead, AsyncWrite}; + +use crate::prelude::*; +use crate::s9pk::merkle_archive::hash::VerifyingWriter; + +pub mod http; +pub mod multi_cursor_file; + +#[async_trait::async_trait] +pub trait FileSource: Send + Sync + Sized + 'static { + type Reader: AsyncRead + Unpin + Send; + async fn size(&self) -> Result; + async fn reader(&self) -> Result; + async fn copy(&self, w: &mut W) -> Result<(), Error> { + tokio::io::copy(&mut self.reader().await?, w).await?; + Ok(()) + } + async fn copy_verify( + &self, + w: &mut W, + verify: Option, + ) -> Result<(), Error> { + let mut w = VerifyingWriter::new(w, verify); + tokio::io::copy(&mut self.reader().await?, &mut w).await?; + w.verify()?; + Ok(()) + } + async fn to_vec(&self, verify: Option) -> Result, Error> { + let mut vec = Vec::with_capacity(self.size().await? as usize); + self.copy_verify(&mut vec, verify).await?; + Ok(vec) + } +} + +#[async_trait::async_trait] +impl FileSource for PathBuf { + type Reader = File; + async fn size(&self) -> Result { + Ok(tokio::fs::metadata(self).await?.len()) + } + async fn reader(&self) -> Result { + Ok(File::open(self).await?) + } +} + +#[async_trait::async_trait] +impl FileSource for Arc<[u8]> { + type Reader = std::io::Cursor; + async fn size(&self) -> Result { + Ok(self.len() as u64) + } + async fn reader(&self) -> Result { + Ok(std::io::Cursor::new(self.clone())) + } + async fn copy(&self, w: &mut W) -> Result<(), Error> { + use tokio::io::AsyncWriteExt; + + w.write_all(&*self).await?; + Ok(()) + } +} + +#[async_trait::async_trait] +pub trait ArchiveSource: Clone + Send + Sync + Sized + 'static { + type Reader: AsyncRead + Unpin + Send; + async fn fetch(&self, position: u64, size: u64) -> Result; + async fn copy_to( + &self, + position: u64, + size: u64, + w: &mut W, + ) -> Result<(), Error> { + tokio::io::copy(&mut self.fetch(position, size).await?, w).await?; + Ok(()) + } + fn section(&self, position: u64, size: u64) -> Section { + Section { + source: self.clone(), + position, + size, + } + } +} + +#[async_trait::async_trait] +impl ArchiveSource for Arc<[u8]> { + type Reader = tokio::io::Take>; + async fn fetch(&self, position: u64, size: u64) -> Result { + use tokio::io::AsyncReadExt; + + let mut cur = std::io::Cursor::new(self.clone()); + cur.set_position(position); + Ok(cur.take(size)) + } +} + +#[derive(Debug)] +pub struct Section { + source: S, + position: u64, + size: u64, +} +#[async_trait::async_trait] +impl FileSource for Section { + type Reader = S::Reader; + async fn size(&self) -> Result { + Ok(self.size) + } + async fn reader(&self) -> Result { + self.source.fetch(self.position, self.size).await + } + async fn copy(&self, w: &mut W) -> Result<(), Error> { + self.source.copy_to(self.position, self.size, w).await + } +} diff --git a/core/src/s9pk/merkle_archive/source/multi_cursor_file.rs b/core/src/s9pk/merkle_archive/source/multi_cursor_file.rs new file mode 100644 index 000000000..cda3e5103 --- /dev/null +++ b/core/src/s9pk/merkle_archive/source/multi_cursor_file.rs @@ -0,0 +1,84 @@ +use std::io::SeekFrom; +use std::os::fd::{AsRawFd, RawFd}; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +use tokio::fs::File; +use tokio::io::AsyncRead; +use tokio::sync::{Mutex, OwnedMutexGuard}; + +use crate::disk::mount::filesystem::loop_dev::LoopDev; +use crate::prelude::*; +use crate::s9pk::merkle_archive::source::{ArchiveSource, Section}; + +#[derive(Clone)] +pub struct MultiCursorFile { + fd: RawFd, + file: Arc>, +} +impl MultiCursorFile { + fn path(&self) -> PathBuf { + Path::new("/proc/self/fd").join(self.fd.to_string()) + } +} +impl From for MultiCursorFile { + fn from(value: File) -> Self { + Self { + fd: value.as_raw_fd(), + file: Arc::new(Mutex::new(value)), + } + } +} + +#[pin_project::pin_project] +pub struct FileSectionReader { + #[pin] + file: OwnedMutexGuard, + remaining: u64, +} +impl AsyncRead for FileSectionReader { + fn poll_read( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> std::task::Poll> { + let this = self.project(); + if *this.remaining == 0 { + return std::task::Poll::Ready(Ok(())); + } + let before = buf.filled().len() as u64; + let res = std::pin::Pin::new(&mut **this.file.get_mut()) + .poll_read(cx, &mut buf.take(*this.remaining as usize)); + *this.remaining = this + .remaining + .saturating_sub(buf.filled().len() as u64 - before); + res + } +} + +#[async_trait::async_trait] +impl ArchiveSource for MultiCursorFile { + type Reader = FileSectionReader; + async fn fetch(&self, position: u64, size: u64) -> Result { + use tokio::io::AsyncSeekExt; + + let mut file = if let Ok(file) = self.file.clone().try_lock_owned() { + file + } else { + Arc::new(Mutex::new(File::open(self.path()).await?)) + .try_lock_owned() + .expect("freshly created") + }; + file.seek(SeekFrom::Start(position)).await?; + Ok(Self::Reader { + file, + remaining: size, + }) + } +} + +impl From> for LoopDev { + fn from(value: Section) -> Self { + LoopDev::new(value.source.path(), value.position, value.size) + } +} diff --git a/core/src/s9pk/merkle_archive/test.rs b/core/src/s9pk/merkle_archive/test.rs new file mode 100644 index 000000000..430ab4f31 --- /dev/null +++ b/core/src/s9pk/merkle_archive/test.rs @@ -0,0 +1,138 @@ +use std::collections::BTreeMap; +use std::io::Cursor; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +use ed25519_dalek::SigningKey; + +use crate::prelude::*; +use crate::s9pk::merkle_archive::directory_contents::DirectoryContents; +use crate::s9pk::merkle_archive::file_contents::FileContents; +use crate::s9pk::merkle_archive::sink::TrackingWriter; +use crate::s9pk::merkle_archive::source::FileSource; +use crate::s9pk::merkle_archive::{Entry, EntryContents, MerkleArchive}; + +/// Creates a MerkleArchive (a1) with the provided files at the provided paths. NOTE: later files can overwrite previous files/directories at the same path +/// Tests: +/// - a1.update_hashes(): returns Ok(_) +/// - a1.serialize(verify: true): returns Ok(s1) +/// - MerkleArchive::deserialize(s1): returns Ok(a2) +/// - a2: contains all expected files with expected content +/// - a2.serialize(verify: true): returns Ok(s2) +/// - s1 == s2 +#[instrument] +fn test(files: Vec<(PathBuf, String)>) -> Result<(), Error> { + let mut root = DirectoryContents::>::new(); + let mut check_set = BTreeMap::::new(); + for (path, content) in files { + if let Err(e) = root.insert_path( + &path, + Entry::new(EntryContents::File(FileContents::new( + content.clone().into_bytes().into(), + ))), + ) { + eprintln!("failed to insert file at {path:?}: {e}"); + } else { + let path = path.strip_prefix("/").unwrap_or(&path); + let mut remaining = check_set.split_off(path); + while { + if let Some((p, s)) = remaining.pop_first() { + if !p.starts_with(path) { + remaining.insert(p, s); + false + } else { + true + } + } else { + false + } + } {} + check_set.append(&mut remaining); + check_set.insert(path.to_owned(), content); + } + } + let key = SigningKey::generate(&mut rand::thread_rng()); + let mut a1 = MerkleArchive::new(root, key); + tokio::runtime::Builder::new_current_thread() + .enable_io() + .build() + .unwrap() + .block_on(async move { + a1.update_hashes(true).await?; + let mut s1 = Vec::new(); + a1.serialize(&mut TrackingWriter::new(0, &mut s1), true) + .await?; + let s1: Arc<[u8]> = s1.into(); + let a2 = MerkleArchive::deserialize(&s1, &mut Cursor::new(s1.clone())).await?; + + for (path, content) in check_set { + match a2 + .contents + .get_path(&path) + .map(|e| (e.as_contents(), e.hash())) + { + Some((EntryContents::File(f), hash)) => { + ensure_code!( + &f.to_vec(hash).await? == content.as_bytes(), + ErrorKind::ParseS9pk, + "File at {path:?} does not match input" + ) + } + _ => { + return Err(Error::new( + eyre!("expected file at {path:?}"), + ErrorKind::ParseS9pk, + )) + } + } + } + + let mut s2 = Vec::new(); + a2.serialize(&mut TrackingWriter::new(0, &mut s2), true) + .await?; + let s2: Arc<[u8]> = s2.into(); + ensure_code!(s1 == s2, ErrorKind::Pack, "s1 does not match s2"); + + Ok(()) + }) +} + +proptest::proptest! { + #[test] + fn property_test(files: Vec<(PathBuf, String)>) { + let files: Vec<(PathBuf, String)> = files.into_iter().filter(|(p, _)| p.file_name().is_some() && p.iter().all(|s| s.to_str().is_some())).collect(); + if let Err(e) = test(files.clone()) { + panic!("{e}\nInput: {files:#?}\n{e:?}"); + } + } +} + +#[test] +fn test_example_1() { + if let Err(e) = test(vec![(Path::new("foo").into(), "bar".into())]) { + panic!("{e}\n{e:?}"); + } +} + +#[test] +fn test_example_2() { + if let Err(e) = test(vec![ + (Path::new("a/a.txt").into(), "a.txt".into()), + (Path::new("a/b/a.txt").into(), "a.txt".into()), + (Path::new("a/b/b/a.txt").into(), "a.txt".into()), + (Path::new("a/b/c.txt").into(), "c.txt".into()), + (Path::new("a/c.txt").into(), "c.txt".into()), + ]) { + panic!("{e}\n{e:?}"); + } +} + +#[test] +fn test_example_3() { + if let Err(e) = test(vec![ + (Path::new("b/a").into(), "𑦪".into()), + (Path::new("a/c/a").into(), "·".into()), + ]) { + panic!("{e}\n{e:?}"); + } +} diff --git a/core/src/s9pk/merkle_archive/varint.rs b/core/src/s9pk/merkle_archive/varint.rs new file mode 100644 index 000000000..479b488e6 --- /dev/null +++ b/core/src/s9pk/merkle_archive/varint.rs @@ -0,0 +1,159 @@ +use integer_encoding::VarInt; +use tokio::io::{AsyncRead, AsyncWrite}; + +use crate::prelude::*; + +/// Most-significant byte, == 0x80 +pub const MSB: u8 = 0b1000_0000; + +const MAX_STR_LEN: u64 = 1024 * 1024; // 1 MiB + +pub fn serialized_varint_size(n: u64) -> u64 { + VarInt::required_space(n) as u64 +} + +pub async fn serialize_varint( + n: u64, + w: &mut W, +) -> Result<(), Error> { + use tokio::io::AsyncWriteExt; + + let mut buf = [0 as u8; 10]; + let b = n.encode_var(&mut buf); + w.write_all(&buf[0..b]).await?; + + Ok(()) +} + +pub fn serialized_varstring_size(s: &str) -> u64 { + serialized_varint_size(s.len() as u64) + s.len() as u64 +} + +pub async fn serialize_varstring( + s: &str, + w: &mut W, +) -> Result<(), Error> { + use tokio::io::AsyncWriteExt; + serialize_varint(s.len() as u64, w).await?; + w.write_all(s.as_bytes()).await?; + Ok(()) +} + +#[derive(Default)] +struct VarIntProcessor { + buf: [u8; 10], + maxsize: usize, + i: usize, +} + +impl VarIntProcessor { + fn new() -> VarIntProcessor { + VarIntProcessor { + maxsize: (std::mem::size_of::() * 8 + 7) / 7, + ..VarIntProcessor::default() + } + } + fn push(&mut self, b: u8) -> Result<(), Error> { + if self.i >= self.maxsize { + return Err(Error::new( + eyre!("Unterminated varint"), + ErrorKind::ParseS9pk, + )); + } + self.buf[self.i] = b; + self.i += 1; + Ok(()) + } + fn finished(&self) -> bool { + self.i > 0 && (self.buf[self.i - 1] & MSB == 0) + } + fn decode(&self) -> Option { + Some(u64::decode_var(&self.buf[0..self.i])?.0) + } +} + +pub async fn deserialize_varint(r: &mut R) -> Result { + use tokio::io::AsyncReadExt; + + let mut buf = [0 as u8; 1]; + let mut p = VarIntProcessor::new(); + + while !p.finished() { + r.read_exact(&mut buf).await?; + + p.push(buf[0])?; + } + + p.decode() + .ok_or_else(|| Error::new(eyre!("Reached EOF"), ErrorKind::ParseS9pk)) +} + +pub async fn deserialize_varstring(r: &mut R) -> Result { + use tokio::io::AsyncReadExt; + + let len = std::cmp::min(deserialize_varint(r).await?, MAX_STR_LEN); + let mut res = String::with_capacity(len as usize); + r.take(len).read_to_string(&mut res).await?; + Ok(res) +} + +#[cfg(test)] +mod test { + use std::io::Cursor; + + use crate::prelude::*; + + fn test_int(n: u64) -> Result<(), Error> { + let n1 = n; + tokio::runtime::Builder::new_current_thread() + .enable_io() + .build() + .unwrap() + .block_on(async move { + let mut v = Vec::new(); + super::serialize_varint(n1, &mut v).await?; + let n2 = super::deserialize_varint(&mut Cursor::new(v)).await?; + + ensure_code!(n1 == n2, ErrorKind::Deserialization, "n1 does not match n2"); + + Ok(()) + }) + } + + fn test_string(s: &str) -> Result<(), Error> { + let s1 = s; + tokio::runtime::Builder::new_current_thread() + .enable_io() + .build() + .unwrap() + .block_on(async move { + let mut v: Vec = Vec::new(); + super::serialize_varstring(&s1, &mut v).await?; + let s2 = super::deserialize_varstring(&mut Cursor::new(v)).await?; + + ensure_code!( + s1 == &s2, + ErrorKind::Deserialization, + "s1 does not match s2" + ); + + Ok(()) + }) + } + + proptest::proptest! { + #[test] + fn proptest_int(n: u64) { + if let Err(e) = test_int(n) { + panic!("{e}\nInput: {n}\n{e:?}"); + } + } + + #[test] + fn proptest_string(s: String) { + if let Err(e) = test_string(&s) { + panic!("{e}\nInput: {s:?}\n{e:?}"); + } + } + } +} diff --git a/core/src/s9pk/merkle_archive/write_queue.rs b/core/src/s9pk/merkle_archive/write_queue.rs new file mode 100644 index 000000000..973ffcf30 --- /dev/null +++ b/core/src/s9pk/merkle_archive/write_queue.rs @@ -0,0 +1,47 @@ +use std::collections::VecDeque; + +use crate::prelude::*; +use crate::s9pk::merkle_archive::sink::Sink; +use crate::s9pk::merkle_archive::source::FileSource; +use crate::s9pk::merkle_archive::{Entry, EntryContents}; +use crate::util::MaybeOwned; + +pub struct WriteQueue<'a, S> { + next_available_position: u64, + queue: VecDeque<&'a Entry>, +} + +impl<'a, S> WriteQueue<'a, S> { + pub fn new(next_available_position: u64) -> Self { + Self { + next_available_position, + queue: VecDeque::new(), + } + } +} +impl<'a, S: FileSource> WriteQueue<'a, S> { + pub async fn add(&mut self, entry: &'a Entry) -> Result { + let res = self.next_available_position; + let size = match entry.as_contents() { + EntryContents::Missing => return Ok(0), + EntryContents::File(f) => f.size().await?, + EntryContents::Directory(d) => d.toc_size(), + }; + self.next_available_position += size; + self.queue.push_back(entry); + Ok(res) + } + pub async fn serialize(&mut self, w: &mut W, verify: bool) -> Result<(), Error> { + loop { + let Some(next) = self.queue.pop_front() else { + break; + }; + match next.as_contents() { + EntryContents::Missing => (), + EntryContents::File(f) => f.serialize_body(w, next.hash.filter(|_| verify)).await?, + EntryContents::Directory(d) => d.serialize_toc(self, w).await?, + } + } + Ok(()) + } +} diff --git a/backend/src/s9pk/builder.rs b/core/src/s9pk/v1/builder.rs similarity index 100% rename from backend/src/s9pk/builder.rs rename to core/src/s9pk/v1/builder.rs diff --git a/backend/src/s9pk/docker.rs b/core/src/s9pk/v1/docker.rs similarity index 100% rename from backend/src/s9pk/docker.rs rename to core/src/s9pk/v1/docker.rs diff --git a/backend/src/s9pk/git_hash.rs b/core/src/s9pk/v1/git_hash.rs similarity index 100% rename from backend/src/s9pk/git_hash.rs rename to core/src/s9pk/v1/git_hash.rs diff --git a/backend/src/s9pk/header.rs b/core/src/s9pk/v1/header.rs similarity index 100% rename from backend/src/s9pk/header.rs rename to core/src/s9pk/v1/header.rs diff --git a/backend/src/s9pk/manifest.rs b/core/src/s9pk/v1/manifest.rs similarity index 100% rename from backend/src/s9pk/manifest.rs rename to core/src/s9pk/v1/manifest.rs diff --git a/backend/src/s9pk/mod.rs b/core/src/s9pk/v1/mod.rs similarity index 100% rename from backend/src/s9pk/mod.rs rename to core/src/s9pk/v1/mod.rs diff --git a/backend/src/s9pk/reader.rs b/core/src/s9pk/v1/reader.rs similarity index 97% rename from backend/src/s9pk/reader.rs rename to core/src/s9pk/v1/reader.rs index e901b1a14..61b5e46a8 100644 --- a/backend/src/s9pk/reader.rs +++ b/core/src/s9pk/v1/reader.rs @@ -220,6 +220,16 @@ impl S9pkReader { &validated_image_ids, )?; + #[cfg(feature = "js-engine")] + if man.containers.is_some() + || matches!(man.main, crate::procedure::PackageProcedure::Script(_)) + { + return Err(Error::new( + eyre!("Right now we don't support the containers and the long running main"), + crate::ErrorKind::ValidateS9pk, + )); + } + if man.replaces.len() >= MAX_REPLACES { return Err(Error::new( eyre!("Cannot have more than {MAX_REPLACES} replaces"), diff --git a/core/src/s9pk/v2/mod.rs b/core/src/s9pk/v2/mod.rs new file mode 100644 index 000000000..be42d0612 --- /dev/null +++ b/core/src/s9pk/v2/mod.rs @@ -0,0 +1,41 @@ +use crate::prelude::*; +use crate::s9pk::merkle_archive::sink::Sink; +use crate::s9pk::merkle_archive::source::{ArchiveSource, FileSource, Section}; +use crate::s9pk::merkle_archive::MerkleArchive; + +const MAGIC_AND_VERSION: &[u8] = &[0x3b, 0x3b, 0x02]; + +pub struct S9pk(MerkleArchive); +impl S9pk { + pub async fn serialize(&mut self, w: &mut W, verify: bool) -> Result<(), Error> { + use tokio::io::AsyncWriteExt; + + w.write_all(MAGIC_AND_VERSION).await?; + self.0.serialize(w, verify).await?; + + Ok(()) + } +} + +impl S9pk> { + pub async fn deserialize(source: &S) -> Result { + use tokio::io::AsyncReadExt; + + let mut header = source + .fetch( + 0, + MAGIC_AND_VERSION.len() as u64 + MerkleArchive::>::header_size(), + ) + .await?; + + let mut magic_version = [0u8; 3]; + header.read_exact(&mut magic_version).await?; + ensure_code!( + &magic_version == MAGIC_AND_VERSION, + ErrorKind::ParseS9pk, + "Invalid Magic or Unexpected Version" + ); + + Ok(Self(MerkleArchive::deserialize(source, &mut header).await?)) + } +} diff --git a/core/src/s9pk/v2/specv2.md b/core/src/s9pk/v2/specv2.md new file mode 100644 index 000000000..08dc3336e --- /dev/null +++ b/core/src/s9pk/v2/specv2.md @@ -0,0 +1,89 @@ +## Magic + +`0x3b3b` + +## Version + +`0x02` (varint) + +## Merkle Archive + +### Header + +- ed25519 pubkey (32B) +- ed25519 signature of TOC sighash (64B) +- TOC sighash: (32B) +- TOC position: (8B: u64 BE) +- TOC size: (8B: u64 BE) + +### TOC + +- number of entries (varint) +- FOREACH section + - name (varstring) + - hash (32B: BLAKE-3 of file contents / TOC sighash) + - TYPE (1B) + - TYPE=MISSING (`0x00`) + - TYPE=FILE (`0x01`) + - position (8B: u64 BE) + - size (8B: u64 BE) + - TYPE=TOC (`0x02`) + - position (8B: u64 BE) + - size (8B: u64 BE) + +#### SigHash +Hash of TOC with all contents MISSING + +### FILE + +`` + +# Example + +`foo/bar/baz.txt` + +ROOT TOC: + - 1 section + - name: foo + hash: sighash('a) + type: TOC + position: 'a + length: _ + +'a: + - 1 section + - name: bar + hash: sighash('b) + type: TOC + position: 'b + size: _ + +'b: + - 2 sections + - name: baz.txt + hash: hash('c) + type: FILE + position: 'c + length: _ + - name: qux + hash: `` + type: MISSING + +'c: `` + +"foo/" +hash: _ +size: 15b + +"bar.txt" +hash: _ +size: 5b + +`` ( + "baz.txt" + hash: _ + size: 2b +) +`` ("hello") +`` ("hi") + diff --git a/backend/.sqlx/query-1ce5254f27de971fd87f5ab66d300f2b22433c86617a0dbf796bf2170186dd2e.json b/core/startos/.sqlx/query-1ce5254f27de971fd87f5ab66d300f2b22433c86617a0dbf796bf2170186dd2e.json similarity index 100% rename from backend/.sqlx/query-1ce5254f27de971fd87f5ab66d300f2b22433c86617a0dbf796bf2170186dd2e.json rename to core/startos/.sqlx/query-1ce5254f27de971fd87f5ab66d300f2b22433c86617a0dbf796bf2170186dd2e.json diff --git a/backend/.sqlx/query-21471490cdc3adb206274cc68e1ea745ffa5da4479478c1fd2158a45324b1930.json b/core/startos/.sqlx/query-21471490cdc3adb206274cc68e1ea745ffa5da4479478c1fd2158a45324b1930.json similarity index 100% rename from backend/.sqlx/query-21471490cdc3adb206274cc68e1ea745ffa5da4479478c1fd2158a45324b1930.json rename to core/startos/.sqlx/query-21471490cdc3adb206274cc68e1ea745ffa5da4479478c1fd2158a45324b1930.json diff --git a/backend/.sqlx/query-28ea34bbde836e0618c5fc9bb7c36e463c20c841a7d6a0eb15be0f24f4a928ec.json b/core/startos/.sqlx/query-28ea34bbde836e0618c5fc9bb7c36e463c20c841a7d6a0eb15be0f24f4a928ec.json similarity index 100% rename from backend/.sqlx/query-28ea34bbde836e0618c5fc9bb7c36e463c20c841a7d6a0eb15be0f24f4a928ec.json rename to core/startos/.sqlx/query-28ea34bbde836e0618c5fc9bb7c36e463c20c841a7d6a0eb15be0f24f4a928ec.json diff --git a/backend/.sqlx/query-4099028a5c0de578255bf54a67cef6cb0f1e9a4e158260700f1639dd4b438997.json b/core/startos/.sqlx/query-4099028a5c0de578255bf54a67cef6cb0f1e9a4e158260700f1639dd4b438997.json similarity index 100% rename from backend/.sqlx/query-4099028a5c0de578255bf54a67cef6cb0f1e9a4e158260700f1639dd4b438997.json rename to core/startos/.sqlx/query-4099028a5c0de578255bf54a67cef6cb0f1e9a4e158260700f1639dd4b438997.json diff --git a/backend/.sqlx/query-4691e3a2ce80b59009ac17124f54f925f61dc5ea371903e62cdffa5d7b67ca96.json b/core/startos/.sqlx/query-4691e3a2ce80b59009ac17124f54f925f61dc5ea371903e62cdffa5d7b67ca96.json similarity index 100% rename from backend/.sqlx/query-4691e3a2ce80b59009ac17124f54f925f61dc5ea371903e62cdffa5d7b67ca96.json rename to core/startos/.sqlx/query-4691e3a2ce80b59009ac17124f54f925f61dc5ea371903e62cdffa5d7b67ca96.json diff --git a/backend/.sqlx/query-4bcfbefb1eb3181343871a1cd7fc3afb81c2be5c681cfa8b4be0ce70610e9c3a.json b/core/startos/.sqlx/query-4bcfbefb1eb3181343871a1cd7fc3afb81c2be5c681cfa8b4be0ce70610e9c3a.json similarity index 100% rename from backend/.sqlx/query-4bcfbefb1eb3181343871a1cd7fc3afb81c2be5c681cfa8b4be0ce70610e9c3a.json rename to core/startos/.sqlx/query-4bcfbefb1eb3181343871a1cd7fc3afb81c2be5c681cfa8b4be0ce70610e9c3a.json diff --git a/backend/.sqlx/query-629be61c3c341c131ddbbff0293a83dbc6afd07cae69d246987f62cf0cc35c2a.json b/core/startos/.sqlx/query-629be61c3c341c131ddbbff0293a83dbc6afd07cae69d246987f62cf0cc35c2a.json similarity index 100% rename from backend/.sqlx/query-629be61c3c341c131ddbbff0293a83dbc6afd07cae69d246987f62cf0cc35c2a.json rename to core/startos/.sqlx/query-629be61c3c341c131ddbbff0293a83dbc6afd07cae69d246987f62cf0cc35c2a.json diff --git a/backend/.sqlx/query-687688055e63d27123cdc89a5bbbd8361776290a9411d527eaf1fdb40bef399d.json b/core/startos/.sqlx/query-687688055e63d27123cdc89a5bbbd8361776290a9411d527eaf1fdb40bef399d.json similarity index 100% rename from backend/.sqlx/query-687688055e63d27123cdc89a5bbbd8361776290a9411d527eaf1fdb40bef399d.json rename to core/startos/.sqlx/query-687688055e63d27123cdc89a5bbbd8361776290a9411d527eaf1fdb40bef399d.json diff --git a/backend/.sqlx/query-6d35ccf780fb2bb62586dd1d3df9c1550a41ee580dad3f49d35cb843ebef10ca.json b/core/startos/.sqlx/query-6d35ccf780fb2bb62586dd1d3df9c1550a41ee580dad3f49d35cb843ebef10ca.json similarity index 100% rename from backend/.sqlx/query-6d35ccf780fb2bb62586dd1d3df9c1550a41ee580dad3f49d35cb843ebef10ca.json rename to core/startos/.sqlx/query-6d35ccf780fb2bb62586dd1d3df9c1550a41ee580dad3f49d35cb843ebef10ca.json diff --git a/backend/.sqlx/query-770c1017734720453dc87b58c385b987c5af5807151ff71a59000014586752e0.json b/core/startos/.sqlx/query-770c1017734720453dc87b58c385b987c5af5807151ff71a59000014586752e0.json similarity index 100% rename from backend/.sqlx/query-770c1017734720453dc87b58c385b987c5af5807151ff71a59000014586752e0.json rename to core/startos/.sqlx/query-770c1017734720453dc87b58c385b987c5af5807151ff71a59000014586752e0.json diff --git a/backend/.sqlx/query-7b64f032d507e8ffe37c41f4c7ad514a66c421a11ab04c26d89a7aa8f6b67210.json b/core/startos/.sqlx/query-7b64f032d507e8ffe37c41f4c7ad514a66c421a11ab04c26d89a7aa8f6b67210.json similarity index 100% rename from backend/.sqlx/query-7b64f032d507e8ffe37c41f4c7ad514a66c421a11ab04c26d89a7aa8f6b67210.json rename to core/startos/.sqlx/query-7b64f032d507e8ffe37c41f4c7ad514a66c421a11ab04c26d89a7aa8f6b67210.json diff --git a/backend/.sqlx/query-7c7a3549c997eb75bf964ea65fbb98a73045adf618696cd838d79203ef5383fb.json b/core/startos/.sqlx/query-7c7a3549c997eb75bf964ea65fbb98a73045adf618696cd838d79203ef5383fb.json similarity index 100% rename from backend/.sqlx/query-7c7a3549c997eb75bf964ea65fbb98a73045adf618696cd838d79203ef5383fb.json rename to core/startos/.sqlx/query-7c7a3549c997eb75bf964ea65fbb98a73045adf618696cd838d79203ef5383fb.json diff --git a/backend/.sqlx/query-7e0649d839927e57fa03ee51a2c9f96a8bdb0fc97ee8a3c6df1069e1e2b98576.json b/core/startos/.sqlx/query-7e0649d839927e57fa03ee51a2c9f96a8bdb0fc97ee8a3c6df1069e1e2b98576.json similarity index 100% rename from backend/.sqlx/query-7e0649d839927e57fa03ee51a2c9f96a8bdb0fc97ee8a3c6df1069e1e2b98576.json rename to core/startos/.sqlx/query-7e0649d839927e57fa03ee51a2c9f96a8bdb0fc97ee8a3c6df1069e1e2b98576.json diff --git a/backend/.sqlx/query-8951b9126fbf60dbb5997241e11e3526b70bccf3e407327917294a993bc17ed5.json b/core/startos/.sqlx/query-8951b9126fbf60dbb5997241e11e3526b70bccf3e407327917294a993bc17ed5.json similarity index 100% rename from backend/.sqlx/query-8951b9126fbf60dbb5997241e11e3526b70bccf3e407327917294a993bc17ed5.json rename to core/startos/.sqlx/query-8951b9126fbf60dbb5997241e11e3526b70bccf3e407327917294a993bc17ed5.json diff --git a/backend/.sqlx/query-94d471bb374b4965c6cbedf8c17bbf6bea226d38efaf6559923c79a36d5ca08c.json b/core/startos/.sqlx/query-94d471bb374b4965c6cbedf8c17bbf6bea226d38efaf6559923c79a36d5ca08c.json similarity index 100% rename from backend/.sqlx/query-94d471bb374b4965c6cbedf8c17bbf6bea226d38efaf6559923c79a36d5ca08c.json rename to core/startos/.sqlx/query-94d471bb374b4965c6cbedf8c17bbf6bea226d38efaf6559923c79a36d5ca08c.json diff --git a/backend/.sqlx/query-95c4ab4c645f3302568c6ff13d85ab58252362694cf0f56999bf60194d20583a.json b/core/startos/.sqlx/query-95c4ab4c645f3302568c6ff13d85ab58252362694cf0f56999bf60194d20583a.json similarity index 100% rename from backend/.sqlx/query-95c4ab4c645f3302568c6ff13d85ab58252362694cf0f56999bf60194d20583a.json rename to core/startos/.sqlx/query-95c4ab4c645f3302568c6ff13d85ab58252362694cf0f56999bf60194d20583a.json diff --git a/backend/.sqlx/query-a60d6e66719325b08dc4ecfacaf337527233c84eee758ac9be967906e5841d27.json b/core/startos/.sqlx/query-a60d6e66719325b08dc4ecfacaf337527233c84eee758ac9be967906e5841d27.json similarity index 100% rename from backend/.sqlx/query-a60d6e66719325b08dc4ecfacaf337527233c84eee758ac9be967906e5841d27.json rename to core/startos/.sqlx/query-a60d6e66719325b08dc4ecfacaf337527233c84eee758ac9be967906e5841d27.json diff --git a/backend/.sqlx/query-a6b0c8909a3a5d6d9156aebfb359424e6b5a1d1402e028219e21726f1ebd282e.json b/core/startos/.sqlx/query-a6b0c8909a3a5d6d9156aebfb359424e6b5a1d1402e028219e21726f1ebd282e.json similarity index 100% rename from backend/.sqlx/query-a6b0c8909a3a5d6d9156aebfb359424e6b5a1d1402e028219e21726f1ebd282e.json rename to core/startos/.sqlx/query-a6b0c8909a3a5d6d9156aebfb359424e6b5a1d1402e028219e21726f1ebd282e.json diff --git a/backend/.sqlx/query-b1147beaaabbed89f2ab8c1e13ec4393a9a8fde2833cf096af766a979d94dee6.json b/core/startos/.sqlx/query-b1147beaaabbed89f2ab8c1e13ec4393a9a8fde2833cf096af766a979d94dee6.json similarity index 100% rename from backend/.sqlx/query-b1147beaaabbed89f2ab8c1e13ec4393a9a8fde2833cf096af766a979d94dee6.json rename to core/startos/.sqlx/query-b1147beaaabbed89f2ab8c1e13ec4393a9a8fde2833cf096af766a979d94dee6.json diff --git a/backend/.sqlx/query-b203820ee1c553a4b246eac74b79bd10d5717b2a0ddecf22330b7d531aac7c5d.json b/core/startos/.sqlx/query-b203820ee1c553a4b246eac74b79bd10d5717b2a0ddecf22330b7d531aac7c5d.json similarity index 100% rename from backend/.sqlx/query-b203820ee1c553a4b246eac74b79bd10d5717b2a0ddecf22330b7d531aac7c5d.json rename to core/startos/.sqlx/query-b203820ee1c553a4b246eac74b79bd10d5717b2a0ddecf22330b7d531aac7c5d.json diff --git a/backend/.sqlx/query-d5117054072476377f3c4f040ea429d4c9b2cf534e76f35c80a2bf60e8599cca.json b/core/startos/.sqlx/query-d5117054072476377f3c4f040ea429d4c9b2cf534e76f35c80a2bf60e8599cca.json similarity index 100% rename from backend/.sqlx/query-d5117054072476377f3c4f040ea429d4c9b2cf534e76f35c80a2bf60e8599cca.json rename to core/startos/.sqlx/query-d5117054072476377f3c4f040ea429d4c9b2cf534e76f35c80a2bf60e8599cca.json diff --git a/backend/.sqlx/query-da71f94b29798d1738d2b10b9a721ea72db8cfb362e7181c8226d9297507c62b.json b/core/startos/.sqlx/query-da71f94b29798d1738d2b10b9a721ea72db8cfb362e7181c8226d9297507c62b.json similarity index 100% rename from backend/.sqlx/query-da71f94b29798d1738d2b10b9a721ea72db8cfb362e7181c8226d9297507c62b.json rename to core/startos/.sqlx/query-da71f94b29798d1738d2b10b9a721ea72db8cfb362e7181c8226d9297507c62b.json diff --git a/backend/.sqlx/query-e185203cf84e43b801dfb23b4159e34aeaef1154dcd3d6811ab504915497ccf7.json b/core/startos/.sqlx/query-e185203cf84e43b801dfb23b4159e34aeaef1154dcd3d6811ab504915497ccf7.json similarity index 100% rename from backend/.sqlx/query-e185203cf84e43b801dfb23b4159e34aeaef1154dcd3d6811ab504915497ccf7.json rename to core/startos/.sqlx/query-e185203cf84e43b801dfb23b4159e34aeaef1154dcd3d6811ab504915497ccf7.json diff --git a/backend/.sqlx/query-e545696735f202f9d13cf22a561f3ff3f9aed7f90027a9ba97634bcb47d772f0.json b/core/startos/.sqlx/query-e545696735f202f9d13cf22a561f3ff3f9aed7f90027a9ba97634bcb47d772f0.json similarity index 100% rename from backend/.sqlx/query-e545696735f202f9d13cf22a561f3ff3f9aed7f90027a9ba97634bcb47d772f0.json rename to core/startos/.sqlx/query-e545696735f202f9d13cf22a561f3ff3f9aed7f90027a9ba97634bcb47d772f0.json diff --git a/backend/.sqlx/query-e5843c5b0e7819b29aa1abf2266799bd4f82e761837b526a0972c3d4439a264d.json b/core/startos/.sqlx/query-e5843c5b0e7819b29aa1abf2266799bd4f82e761837b526a0972c3d4439a264d.json similarity index 100% rename from backend/.sqlx/query-e5843c5b0e7819b29aa1abf2266799bd4f82e761837b526a0972c3d4439a264d.json rename to core/startos/.sqlx/query-e5843c5b0e7819b29aa1abf2266799bd4f82e761837b526a0972c3d4439a264d.json diff --git a/backend/.sqlx/query-e95322a8e2ae3b93f1e974b24c0b81803f1e9ec9e8ebbf15cafddfc1c5a028ed.json b/core/startos/.sqlx/query-e95322a8e2ae3b93f1e974b24c0b81803f1e9ec9e8ebbf15cafddfc1c5a028ed.json similarity index 100% rename from backend/.sqlx/query-e95322a8e2ae3b93f1e974b24c0b81803f1e9ec9e8ebbf15cafddfc1c5a028ed.json rename to core/startos/.sqlx/query-e95322a8e2ae3b93f1e974b24c0b81803f1e9ec9e8ebbf15cafddfc1c5a028ed.json diff --git a/backend/.sqlx/query-eb750adaa305bdbf3c5b70aaf59139c7b7569602adb58f2d6b3a94da4f167b0a.json b/core/startos/.sqlx/query-eb750adaa305bdbf3c5b70aaf59139c7b7569602adb58f2d6b3a94da4f167b0a.json similarity index 100% rename from backend/.sqlx/query-eb750adaa305bdbf3c5b70aaf59139c7b7569602adb58f2d6b3a94da4f167b0a.json rename to core/startos/.sqlx/query-eb750adaa305bdbf3c5b70aaf59139c7b7569602adb58f2d6b3a94da4f167b0a.json diff --git a/backend/.sqlx/query-ecc765d8205c0876956f95f76944ac6a5f34dd820c4073b7728c7067aab9fded.json b/core/startos/.sqlx/query-ecc765d8205c0876956f95f76944ac6a5f34dd820c4073b7728c7067aab9fded.json similarity index 100% rename from backend/.sqlx/query-ecc765d8205c0876956f95f76944ac6a5f34dd820c4073b7728c7067aab9fded.json rename to core/startos/.sqlx/query-ecc765d8205c0876956f95f76944ac6a5f34dd820c4073b7728c7067aab9fded.json diff --git a/backend/.sqlx/query-f6d1c5ef0f9d9577bea8382318967b9deb46da75788c7fe6082b43821c22d556.json b/core/startos/.sqlx/query-f6d1c5ef0f9d9577bea8382318967b9deb46da75788c7fe6082b43821c22d556.json similarity index 100% rename from backend/.sqlx/query-f6d1c5ef0f9d9577bea8382318967b9deb46da75788c7fe6082b43821c22d556.json rename to core/startos/.sqlx/query-f6d1c5ef0f9d9577bea8382318967b9deb46da75788c7fe6082b43821c22d556.json diff --git a/backend/.sqlx/query-f7d2dae84613bcef330f7403352cc96547f3f6dbec11bf2eadfaf53ad8ab51b5.json b/core/startos/.sqlx/query-f7d2dae84613bcef330f7403352cc96547f3f6dbec11bf2eadfaf53ad8ab51b5.json similarity index 100% rename from backend/.sqlx/query-f7d2dae84613bcef330f7403352cc96547f3f6dbec11bf2eadfaf53ad8ab51b5.json rename to core/startos/.sqlx/query-f7d2dae84613bcef330f7403352cc96547f3f6dbec11bf2eadfaf53ad8ab51b5.json diff --git a/backend/.sqlx/query-fe6e4f09f3028e5b6b6259e86cbad285680ce157aae9d7837ac020c8b2945e7f.json b/core/startos/.sqlx/query-fe6e4f09f3028e5b6b6259e86cbad285680ce157aae9d7837ac020c8b2945e7f.json similarity index 100% rename from backend/.sqlx/query-fe6e4f09f3028e5b6b6259e86cbad285680ce157aae9d7837ac020c8b2945e7f.json rename to core/startos/.sqlx/query-fe6e4f09f3028e5b6b6259e86cbad285680ce157aae9d7837ac020c8b2945e7f.json diff --git a/backend/Cargo.toml b/core/startos/Cargo.toml similarity index 91% rename from backend/Cargo.toml rename to core/startos/Cargo.toml index 77da1b5a3..e371561d7 100644 --- a/backend/Cargo.toml +++ b/core/startos/Cargo.toml @@ -30,7 +30,7 @@ avahi = ["avahi-sys"] avahi-alias = ["avahi"] cli = [] daemon = [] -default = ["cli", "sdk", "daemon", "js_engine"] +default = ["cli", "sdk", "daemon", "js-engine"] dev = [] docker = [] sdk = [] @@ -53,6 +53,7 @@ base64 = "0.21.4" base64ct = "1.6.0" basic-cookies = "0.1.4" bimap = { version = "0.6.2", features = ["serde"] } +blake3 = "1.5.0" bytes = "1" chrono = { version = "0.4.31", features = ["serde"] } clap = "3.2.25" @@ -72,14 +73,14 @@ ed25519-dalek = { version = "2.0.0", features = [ "digest", ] } ed25519-dalek-v1 = { package = "ed25519-dalek", version = "1" } -embassy_container_init = { path = "../libs/embassy_container_init" } +container-init = { path = "../container-init" } emver = { version = "0.1.7", git = "https://github.com/Start9Labs/emver-rs.git", features = [ "serde", ] } fd-lock-rs = "0.1.4" futures = "0.3.28" gpt = "3.1.0" -helpers = { path = "../libs/helpers" } +helpers = { path = "../helpers" } hex = "0.4.3" hmac = "0.12.1" http = "0.2.9" @@ -94,6 +95,7 @@ imbl-value = { git = "https://github.com/Start9Labs/imbl-value.git" } include_dir = "0.7.3" indexmap = { version = "2.0.2", features = ["serde"] } indicatif = { version = "0.17.7", features = ["tokio"] } +integer-encoding = { version = "4.0.0", features = ["tokio_async"] } ipnet = { version = "2.8.0", features = ["serde"] } iprange = { version = "0.6.7", features = ["serde"] } isocountry = "0.3.2" @@ -101,13 +103,13 @@ itertools = "0.11.0" jaq-core = "0.10.1" jaq-std = "0.10.0" josekit = "0.8.4" -js_engine = { path = '../libs/js_engine', optional = true } +js-engine = { path = '../js-engine', optional = true } jsonpath_lib = { git = "https://github.com/Start9Labs/jsonpath.git" } lazy_static = "1.4.0" libc = "0.2.149" log = "0.4.20" mbrman = "0.5.2" -models = { version = "*", path = "../libs/models" } +models = { version = "*", path = "../models" } new_mime_guess = "4" nix = { version = "0.27.1", features = ["user", "process", "signal", "fs"] } nom = "7.1.3" @@ -116,7 +118,7 @@ num_enum = "0.7.0" openssh-keys = "0.6.2" openssl = { version = "0.10.57", features = ["vendored"] } p256 = { version = "0.13.2", features = ["pem"] } -patch-db = { version = "*", path = "../patch-db/patch-db", features = [ +patch-db = { version = "*", path = "../../patch-db/patch-db", features = [ "trace", ] } pbkdf2 = "0.12.2" @@ -174,6 +176,9 @@ zeroize = "1.6.0" [profile.test] opt-level = 3 +[profile.dev] +opt-level = 3 + [profile.dev.package.backtrace] opt-level = 3 diff --git a/backend/deny.toml b/core/startos/deny.toml similarity index 100% rename from backend/deny.toml rename to core/startos/deny.toml diff --git a/backend/migrations/20210629193146_Init.sql b/core/startos/migrations/20210629193146_Init.sql similarity index 100% rename from backend/migrations/20210629193146_Init.sql rename to core/startos/migrations/20210629193146_Init.sql diff --git a/backend/migrations/20230118185232_NetworkKeys.sql b/core/startos/migrations/20230118185232_NetworkKeys.sql similarity index 100% rename from backend/migrations/20230118185232_NetworkKeys.sql rename to core/startos/migrations/20230118185232_NetworkKeys.sql diff --git a/backend/src/account.rs b/core/startos/src/account.rs similarity index 100% rename from backend/src/account.rs rename to core/startos/src/account.rs diff --git a/backend/src/action.rs b/core/startos/src/action.rs similarity index 100% rename from backend/src/action.rs rename to core/startos/src/action.rs diff --git a/backend/src/assets/adjectives.txt b/core/startos/src/assets/adjectives.txt similarity index 100% rename from backend/src/assets/adjectives.txt rename to core/startos/src/assets/adjectives.txt diff --git a/backend/src/assets/nouns.txt b/core/startos/src/assets/nouns.txt similarity index 100% rename from backend/src/assets/nouns.txt rename to core/startos/src/assets/nouns.txt diff --git a/backend/src/auth.rs b/core/startos/src/auth.rs similarity index 100% rename from backend/src/auth.rs rename to core/startos/src/auth.rs diff --git a/backend/src/backup/backup_bulk.rs b/core/startos/src/backup/backup_bulk.rs similarity index 100% rename from backend/src/backup/backup_bulk.rs rename to core/startos/src/backup/backup_bulk.rs diff --git a/backend/src/backup/mod.rs b/core/startos/src/backup/mod.rs similarity index 100% rename from backend/src/backup/mod.rs rename to core/startos/src/backup/mod.rs diff --git a/backend/src/backup/os.rs b/core/startos/src/backup/os.rs similarity index 100% rename from backend/src/backup/os.rs rename to core/startos/src/backup/os.rs diff --git a/backend/src/backup/restore.rs b/core/startos/src/backup/restore.rs similarity index 100% rename from backend/src/backup/restore.rs rename to core/startos/src/backup/restore.rs diff --git a/backend/src/backup/target/cifs.rs b/core/startos/src/backup/target/cifs.rs similarity index 100% rename from backend/src/backup/target/cifs.rs rename to core/startos/src/backup/target/cifs.rs diff --git a/backend/src/backup/target/mod.rs b/core/startos/src/backup/target/mod.rs similarity index 100% rename from backend/src/backup/target/mod.rs rename to core/startos/src/backup/target/mod.rs diff --git a/backend/src/bins/avahi_alias.rs b/core/startos/src/bins/avahi_alias.rs similarity index 100% rename from backend/src/bins/avahi_alias.rs rename to core/startos/src/bins/avahi_alias.rs diff --git a/backend/src/bins/deprecated.rs b/core/startos/src/bins/deprecated.rs similarity index 100% rename from backend/src/bins/deprecated.rs rename to core/startos/src/bins/deprecated.rs diff --git a/backend/src/bins/mod.rs b/core/startos/src/bins/mod.rs similarity index 98% rename from backend/src/bins/mod.rs rename to core/startos/src/bins/mod.rs index e131d22c4..c391338fe 100644 --- a/backend/src/bins/mod.rs +++ b/core/startos/src/bins/mod.rs @@ -5,7 +5,7 @@ pub mod avahi_alias; pub mod deprecated; #[cfg(feature = "cli")] pub mod start_cli; -#[cfg(feature = "js_engine")] +#[cfg(feature = "js-engine")] pub mod start_deno; #[cfg(feature = "daemon")] pub mod start_init; diff --git a/backend/src/bins/start_cli.rs b/core/startos/src/bins/start_cli.rs similarity index 100% rename from backend/src/bins/start_cli.rs rename to core/startos/src/bins/start_cli.rs diff --git a/backend/src/bins/start_deno.rs b/core/startos/src/bins/start_deno.rs similarity index 95% rename from backend/src/bins/start_deno.rs rename to core/startos/src/bins/start_deno.rs index 0be507082..8f5a1451a 100644 --- a/backend/src/bins/start_deno.rs +++ b/core/startos/src/bins/start_deno.rs @@ -4,7 +4,7 @@ use serde_json::Value; use crate::procedure::js_scripts::ExecuteArgs; use crate::s9pk::manifest::PackageId; -use crate::util::serde::{display_serializable, parse_stdin_deserializable}; +use crate::util::serde::{display_serializable, parse_stdin_deserializable, IoFormat}; use crate::version::{Current, VersionT}; use crate::Error; @@ -23,6 +23,9 @@ fn deno_api() -> Result<(), Error> { #[command(cli_only, display(display_serializable))] async fn execute( #[arg(stdin, parse(parse_stdin_deserializable))] arg: ExecuteArgs, + #[allow(unused_variables)] + #[arg(long = "format")] + format: Option, ) -> Result, Error> { let ExecuteArgs { procedure, @@ -41,6 +44,9 @@ async fn execute( #[command(cli_only, display(display_serializable))] async fn sandbox( #[arg(stdin, parse(parse_stdin_deserializable))] arg: ExecuteArgs, + #[allow(unused_variables)] + #[arg(long = "format")] + format: Option, ) -> Result, Error> { let ExecuteArgs { procedure, diff --git a/backend/src/bins/start_init.rs b/core/startos/src/bins/start_init.rs similarity index 98% rename from backend/src/bins/start_init.rs rename to core/startos/src/bins/start_init.rs index 0440e0ad6..f189c3723 100644 --- a/backend/src/bins/start_init.rs +++ b/core/startos/src/bins/start_init.rs @@ -32,19 +32,19 @@ async fn setup_or_init(cfg_path: Option) -> Result, Er .arg("-sf") .arg("/usr/lib/startos/scripts/fake-apt") .arg("/usr/local/bin/apt") - .invoke(crate::ErrorKind::OpenSsh) + .invoke(crate::ErrorKind::Filesystem) .await?; Command::new("ln") .arg("-sf") .arg("/usr/lib/startos/scripts/fake-apt") .arg("/usr/local/bin/apt-get") - .invoke(crate::ErrorKind::OpenSsh) + .invoke(crate::ErrorKind::Filesystem) .await?; Command::new("ln") .arg("-sf") .arg("/usr/lib/startos/scripts/fake-apt") .arg("/usr/local/bin/aptitude") - .invoke(crate::ErrorKind::OpenSsh) + .invoke(crate::ErrorKind::Filesystem) .await?; Command::new("make-ssl-cert") diff --git a/backend/src/bins/start_sdk.rs b/core/startos/src/bins/start_sdk.rs similarity index 100% rename from backend/src/bins/start_sdk.rs rename to core/startos/src/bins/start_sdk.rs diff --git a/backend/src/bins/startd.rs b/core/startos/src/bins/startd.rs similarity index 100% rename from backend/src/bins/startd.rs rename to core/startos/src/bins/startd.rs diff --git a/backend/src/config/action.rs b/core/startos/src/config/action.rs similarity index 100% rename from backend/src/config/action.rs rename to core/startos/src/config/action.rs diff --git a/backend/src/config/hook.rs b/core/startos/src/config/hook.rs similarity index 100% rename from backend/src/config/hook.rs rename to core/startos/src/config/hook.rs diff --git a/backend/src/config/mod.rs b/core/startos/src/config/mod.rs similarity index 100% rename from backend/src/config/mod.rs rename to core/startos/src/config/mod.rs diff --git a/backend/src/config/spec.rs b/core/startos/src/config/spec.rs similarity index 100% rename from backend/src/config/spec.rs rename to core/startos/src/config/spec.rs diff --git a/backend/src/config/util.rs b/core/startos/src/config/util.rs similarity index 100% rename from backend/src/config/util.rs rename to core/startos/src/config/util.rs diff --git a/backend/src/context/cli.rs b/core/startos/src/context/cli.rs similarity index 100% rename from backend/src/context/cli.rs rename to core/startos/src/context/cli.rs diff --git a/backend/src/context/diagnostic.rs b/core/startos/src/context/diagnostic.rs similarity index 100% rename from backend/src/context/diagnostic.rs rename to core/startos/src/context/diagnostic.rs diff --git a/backend/src/context/install.rs b/core/startos/src/context/install.rs similarity index 100% rename from backend/src/context/install.rs rename to core/startos/src/context/install.rs diff --git a/backend/src/context/mod.rs b/core/startos/src/context/mod.rs similarity index 100% rename from backend/src/context/mod.rs rename to core/startos/src/context/mod.rs diff --git a/backend/src/context/rpc.rs b/core/startos/src/context/rpc.rs similarity index 100% rename from backend/src/context/rpc.rs rename to core/startos/src/context/rpc.rs diff --git a/backend/src/context/sdk.rs b/core/startos/src/context/sdk.rs similarity index 100% rename from backend/src/context/sdk.rs rename to core/startos/src/context/sdk.rs diff --git a/backend/src/context/setup.rs b/core/startos/src/context/setup.rs similarity index 100% rename from backend/src/context/setup.rs rename to core/startos/src/context/setup.rs diff --git a/backend/src/control.rs b/core/startos/src/control.rs similarity index 100% rename from backend/src/control.rs rename to core/startos/src/control.rs diff --git a/backend/src/core/mod.rs b/core/startos/src/core/mod.rs similarity index 100% rename from backend/src/core/mod.rs rename to core/startos/src/core/mod.rs diff --git a/backend/src/core/rpc_continuations.rs b/core/startos/src/core/rpc_continuations.rs similarity index 100% rename from backend/src/core/rpc_continuations.rs rename to core/startos/src/core/rpc_continuations.rs diff --git a/backend/src/db/mod.rs b/core/startos/src/db/mod.rs similarity index 100% rename from backend/src/db/mod.rs rename to core/startos/src/db/mod.rs diff --git a/backend/src/db/model.rs b/core/startos/src/db/model.rs similarity index 98% rename from backend/src/db/model.rs rename to core/startos/src/db/model.rs index e6b091be1..15d404d49 100644 --- a/backend/src/db/model.rs +++ b/core/startos/src/db/model.rs @@ -88,8 +88,11 @@ impl Database { }, package_data: AllPackageData::default(), lan_port_forwards: LanPortForwards::new(), - ui: serde_json::from_str(include_str!("../../../frontend/patchdb-ui-seed.json")) - .unwrap(), + ui: serde_json::from_str(include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../web/patchdb-ui-seed.json" + ))) + .unwrap(), } } } diff --git a/backend/src/db/package.rs b/core/startos/src/db/package.rs similarity index 100% rename from backend/src/db/package.rs rename to core/startos/src/db/package.rs diff --git a/backend/src/db/prelude.rs b/core/startos/src/db/prelude.rs similarity index 100% rename from backend/src/db/prelude.rs rename to core/startos/src/db/prelude.rs diff --git a/backend/src/dependencies.rs b/core/startos/src/dependencies.rs similarity index 100% rename from backend/src/dependencies.rs rename to core/startos/src/dependencies.rs diff --git a/backend/src/developer/mod.rs b/core/startos/src/developer/mod.rs similarity index 100% rename from backend/src/developer/mod.rs rename to core/startos/src/developer/mod.rs diff --git a/backend/src/diagnostic.rs b/core/startos/src/diagnostic.rs similarity index 100% rename from backend/src/diagnostic.rs rename to core/startos/src/diagnostic.rs diff --git a/backend/src/disk/fsck/btrfs.rs b/core/startos/src/disk/fsck/btrfs.rs similarity index 100% rename from backend/src/disk/fsck/btrfs.rs rename to core/startos/src/disk/fsck/btrfs.rs diff --git a/backend/src/disk/fsck/ext4.rs b/core/startos/src/disk/fsck/ext4.rs similarity index 100% rename from backend/src/disk/fsck/ext4.rs rename to core/startos/src/disk/fsck/ext4.rs diff --git a/backend/src/disk/fsck/mod.rs b/core/startos/src/disk/fsck/mod.rs similarity index 100% rename from backend/src/disk/fsck/mod.rs rename to core/startos/src/disk/fsck/mod.rs diff --git a/backend/src/disk/main.rs b/core/startos/src/disk/main.rs similarity index 100% rename from backend/src/disk/main.rs rename to core/startos/src/disk/main.rs diff --git a/backend/src/disk/mod.rs b/core/startos/src/disk/mod.rs similarity index 100% rename from backend/src/disk/mod.rs rename to core/startos/src/disk/mod.rs diff --git a/backend/src/disk/mount/backup.rs b/core/startos/src/disk/mount/backup.rs similarity index 100% rename from backend/src/disk/mount/backup.rs rename to core/startos/src/disk/mount/backup.rs diff --git a/backend/src/disk/mount/filesystem/bind.rs b/core/startos/src/disk/mount/filesystem/bind.rs similarity index 100% rename from backend/src/disk/mount/filesystem/bind.rs rename to core/startos/src/disk/mount/filesystem/bind.rs diff --git a/backend/src/disk/mount/filesystem/block_dev.rs b/core/startos/src/disk/mount/filesystem/block_dev.rs similarity index 100% rename from backend/src/disk/mount/filesystem/block_dev.rs rename to core/startos/src/disk/mount/filesystem/block_dev.rs diff --git a/backend/src/disk/mount/filesystem/cifs.rs b/core/startos/src/disk/mount/filesystem/cifs.rs similarity index 100% rename from backend/src/disk/mount/filesystem/cifs.rs rename to core/startos/src/disk/mount/filesystem/cifs.rs diff --git a/backend/src/disk/mount/filesystem/ecryptfs.rs b/core/startos/src/disk/mount/filesystem/ecryptfs.rs similarity index 100% rename from backend/src/disk/mount/filesystem/ecryptfs.rs rename to core/startos/src/disk/mount/filesystem/ecryptfs.rs diff --git a/backend/src/disk/mount/filesystem/efivarfs.rs b/core/startos/src/disk/mount/filesystem/efivarfs.rs similarity index 100% rename from backend/src/disk/mount/filesystem/efivarfs.rs rename to core/startos/src/disk/mount/filesystem/efivarfs.rs diff --git a/backend/src/disk/mount/filesystem/httpdirfs.rs b/core/startos/src/disk/mount/filesystem/httpdirfs.rs similarity index 100% rename from backend/src/disk/mount/filesystem/httpdirfs.rs rename to core/startos/src/disk/mount/filesystem/httpdirfs.rs diff --git a/backend/src/disk/mount/filesystem/label.rs b/core/startos/src/disk/mount/filesystem/label.rs similarity index 100% rename from backend/src/disk/mount/filesystem/label.rs rename to core/startos/src/disk/mount/filesystem/label.rs diff --git a/core/startos/src/disk/mount/filesystem/loop_dev.rs b/core/startos/src/disk/mount/filesystem/loop_dev.rs new file mode 100644 index 000000000..28a18597d --- /dev/null +++ b/core/startos/src/disk/mount/filesystem/loop_dev.rs @@ -0,0 +1,89 @@ +use std::os::unix::ffi::OsStrExt; +use std::path::Path; + +use async_trait::async_trait; +use digest::generic_array::GenericArray; +use digest::{Digest, OutputSizeUser}; +use serde::{Deserialize, Serialize}; +use sha2::Sha256; + +use super::{FileSystem, MountType, ReadOnly}; +use crate::util::Invoke; +use crate::{Error, ResultExt}; + +pub async fn mount( + logicalname: impl AsRef, + offset: u64, + size: u64, + mountpoint: impl AsRef, + mount_type: MountType, +) -> Result<(), Error> { + tokio::fs::create_dir_all(mountpoint.as_ref()).await?; + let mut opts = format!("loop,offset={offset},sizelimit={size}"); + if mount_type == ReadOnly { + opts += ",ro"; + } + + tokio::process::Command::new("mount") + .arg(logicalname.as_ref()) + .arg(mountpoint.as_ref()) + .arg("-o") + .arg(opts) + .invoke(crate::ErrorKind::Filesystem) + .await?; + Ok(()) +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct LoopDev> { + logicalname: LogicalName, + offset: u64, + size: u64, +} +impl> LoopDev { + pub fn new(logicalname: LogicalName, offset: u64, size: u64) -> Self { + Self { + logicalname, + offset, + size, + } + } +} +#[async_trait] +impl + Send + Sync> FileSystem for LoopDev { + async fn mount + Send + Sync>( + &self, + mountpoint: P, + mount_type: MountType, + ) -> Result<(), Error> { + mount( + self.logicalname.as_ref(), + self.offset, + self.size, + mountpoint, + mount_type, + ) + .await + } + async fn source_hash( + &self, + ) -> Result::OutputSize>, Error> { + let mut sha = Sha256::new(); + sha.update("LoopDev"); + sha.update( + tokio::fs::canonicalize(self.logicalname.as_ref()) + .await + .with_ctx(|_| { + ( + crate::ErrorKind::Filesystem, + self.logicalname.as_ref().display().to_string(), + ) + })? + .as_os_str() + .as_bytes(), + ); + sha.update(&u64::to_be_bytes(self.offset)[..]); + Ok(sha.finalize()) + } +} diff --git a/backend/src/disk/mount/filesystem/mod.rs b/core/startos/src/disk/mount/filesystem/mod.rs similarity index 97% rename from backend/src/disk/mount/filesystem/mod.rs rename to core/startos/src/disk/mount/filesystem/mod.rs index 00247e0dd..11a6671df 100644 --- a/backend/src/disk/mount/filesystem/mod.rs +++ b/core/startos/src/disk/mount/filesystem/mod.rs @@ -14,6 +14,7 @@ pub mod ecryptfs; pub mod efivarfs; pub mod httpdirfs; pub mod label; +pub mod loop_dev; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum MountType { diff --git a/backend/src/disk/mount/guard.rs b/core/startos/src/disk/mount/guard.rs similarity index 100% rename from backend/src/disk/mount/guard.rs rename to core/startos/src/disk/mount/guard.rs diff --git a/backend/src/disk/mount/mod.rs b/core/startos/src/disk/mount/mod.rs similarity index 100% rename from backend/src/disk/mount/mod.rs rename to core/startos/src/disk/mount/mod.rs diff --git a/backend/src/disk/mount/util.rs b/core/startos/src/disk/mount/util.rs similarity index 100% rename from backend/src/disk/mount/util.rs rename to core/startos/src/disk/mount/util.rs diff --git a/backend/src/disk/util.rs b/core/startos/src/disk/util.rs similarity index 100% rename from backend/src/disk/util.rs rename to core/startos/src/disk/util.rs diff --git a/backend/src/error.rs b/core/startos/src/error.rs similarity index 100% rename from backend/src/error.rs rename to core/startos/src/error.rs diff --git a/backend/src/firmware.rs b/core/startos/src/firmware.rs similarity index 100% rename from backend/src/firmware.rs rename to core/startos/src/firmware.rs diff --git a/backend/src/hostname.rs b/core/startos/src/hostname.rs similarity index 100% rename from backend/src/hostname.rs rename to core/startos/src/hostname.rs diff --git a/backend/src/init.rs b/core/startos/src/init.rs similarity index 100% rename from backend/src/init.rs rename to core/startos/src/init.rs diff --git a/backend/src/inspect.rs b/core/startos/src/inspect.rs similarity index 100% rename from backend/src/inspect.rs rename to core/startos/src/inspect.rs diff --git a/backend/src/install/cleanup.rs b/core/startos/src/install/cleanup.rs similarity index 100% rename from backend/src/install/cleanup.rs rename to core/startos/src/install/cleanup.rs diff --git a/backend/src/install/mod.rs b/core/startos/src/install/mod.rs similarity index 100% rename from backend/src/install/mod.rs rename to core/startos/src/install/mod.rs diff --git a/backend/src/install/package-icon.png b/core/startos/src/install/package-icon.png similarity index 100% rename from backend/src/install/package-icon.png rename to core/startos/src/install/package-icon.png diff --git a/backend/src/install/progress.rs b/core/startos/src/install/progress.rs similarity index 100% rename from backend/src/install/progress.rs rename to core/startos/src/install/progress.rs diff --git a/backend/src/install/update.rs b/core/startos/src/install/update.rs similarity index 100% rename from backend/src/install/update.rs rename to core/startos/src/install/update.rs diff --git a/backend/src/lib.rs b/core/startos/src/lib.rs similarity index 100% rename from backend/src/lib.rs rename to core/startos/src/lib.rs diff --git a/backend/src/logs.rs b/core/startos/src/logs.rs similarity index 100% rename from backend/src/logs.rs rename to core/startos/src/logs.rs diff --git a/backend/src/main.rs b/core/startos/src/main.rs similarity index 100% rename from backend/src/main.rs rename to core/startos/src/main.rs diff --git a/backend/src/manager/health.rs b/core/startos/src/manager/health.rs similarity index 100% rename from backend/src/manager/health.rs rename to core/startos/src/manager/health.rs diff --git a/backend/src/manager/js_api.rs b/core/startos/src/manager/js_api.rs similarity index 100% rename from backend/src/manager/js_api.rs rename to core/startos/src/manager/js_api.rs diff --git a/backend/src/manager/manager_container.rs b/core/startos/src/manager/manager_container.rs similarity index 100% rename from backend/src/manager/manager_container.rs rename to core/startos/src/manager/manager_container.rs diff --git a/backend/src/manager/manager_map.rs b/core/startos/src/manager/manager_map.rs similarity index 100% rename from backend/src/manager/manager_map.rs rename to core/startos/src/manager/manager_map.rs diff --git a/backend/src/manager/manager_seed.rs b/core/startos/src/manager/manager_seed.rs similarity index 100% rename from backend/src/manager/manager_seed.rs rename to core/startos/src/manager/manager_seed.rs diff --git a/backend/src/manager/mod.rs b/core/startos/src/manager/mod.rs similarity index 99% rename from backend/src/manager/mod.rs rename to core/startos/src/manager/mod.rs index f8f9ff16d..62653c305 100644 --- a/backend/src/manager/mod.rs +++ b/core/startos/src/manager/mod.rs @@ -5,7 +5,7 @@ use std::task::Poll; use std::time::Duration; use color_eyre::eyre::eyre; -use embassy_container_init::ProcessGroupId; +use container_init::ProcessGroupId; use futures::future::BoxFuture; use futures::{Future, FutureExt, TryFutureExt}; use helpers::UnixRpcClient; @@ -850,7 +850,7 @@ async fn send_signal(manager: &Manager, gid: Arc, signal: Signal) -> Result if let Some(rpc_client) = manager.rpc_client() { let main_gid = *gid.main_gid.0.borrow(); let next_gid = gid.new_gid(); - #[cfg(feature = "js_engine")] + #[cfg(feature = "js-engine")] if let Err(e) = crate::procedure::js_scripts::JsProcedure::default() .execute::<_, NoOutput>( &manager.seed.ctx.datadir, @@ -858,7 +858,7 @@ async fn send_signal(manager: &Manager, gid: Arc, signal: Signal) -> Result &manager.seed.manifest.version, ProcedureName::Signal, &manager.seed.manifest.volumes, - Some(embassy_container_init::SignalGroupParams { + Some(container_init::SignalGroupParams { gid: main_gid, signal: signal as u32, }), diff --git a/backend/src/manager/persistent_container.rs b/core/startos/src/manager/persistent_container.rs similarity index 100% rename from backend/src/manager/persistent_container.rs rename to core/startos/src/manager/persistent_container.rs diff --git a/backend/src/manager/start_stop.rs b/core/startos/src/manager/start_stop.rs similarity index 100% rename from backend/src/manager/start_stop.rs rename to core/startos/src/manager/start_stop.rs diff --git a/backend/src/manager/transition_state.rs b/core/startos/src/manager/transition_state.rs similarity index 100% rename from backend/src/manager/transition_state.rs rename to core/startos/src/manager/transition_state.rs diff --git a/backend/src/middleware/auth.rs b/core/startos/src/middleware/auth.rs similarity index 100% rename from backend/src/middleware/auth.rs rename to core/startos/src/middleware/auth.rs diff --git a/backend/src/middleware/cors.rs b/core/startos/src/middleware/cors.rs similarity index 100% rename from backend/src/middleware/cors.rs rename to core/startos/src/middleware/cors.rs diff --git a/backend/src/middleware/db.rs b/core/startos/src/middleware/db.rs similarity index 100% rename from backend/src/middleware/db.rs rename to core/startos/src/middleware/db.rs diff --git a/backend/src/middleware/diagnostic.rs b/core/startos/src/middleware/diagnostic.rs similarity index 100% rename from backend/src/middleware/diagnostic.rs rename to core/startos/src/middleware/diagnostic.rs diff --git a/backend/src/middleware/encrypt.rs b/core/startos/src/middleware/encrypt.rs similarity index 100% rename from backend/src/middleware/encrypt.rs rename to core/startos/src/middleware/encrypt.rs diff --git a/backend/src/middleware/mod.rs b/core/startos/src/middleware/mod.rs similarity index 100% rename from backend/src/middleware/mod.rs rename to core/startos/src/middleware/mod.rs diff --git a/backend/src/migrate.load b/core/startos/src/migrate.load similarity index 100% rename from backend/src/migrate.load rename to core/startos/src/migrate.load diff --git a/backend/src/migration.rs b/core/startos/src/migration.rs similarity index 100% rename from backend/src/migration.rs rename to core/startos/src/migration.rs diff --git a/backend/src/net/cert-local.csr.conf.template b/core/startos/src/net/cert-local.csr.conf.template similarity index 100% rename from backend/src/net/cert-local.csr.conf.template rename to core/startos/src/net/cert-local.csr.conf.template diff --git a/backend/src/net/dhcp.rs b/core/startos/src/net/dhcp.rs similarity index 100% rename from backend/src/net/dhcp.rs rename to core/startos/src/net/dhcp.rs diff --git a/backend/src/net/dns.rs b/core/startos/src/net/dns.rs similarity index 100% rename from backend/src/net/dns.rs rename to core/startos/src/net/dns.rs diff --git a/backend/src/net/forward.rs b/core/startos/src/net/forward.rs similarity index 100% rename from backend/src/net/forward.rs rename to core/startos/src/net/forward.rs diff --git a/backend/src/net/interface.rs b/core/startos/src/net/interface.rs similarity index 100% rename from backend/src/net/interface.rs rename to core/startos/src/net/interface.rs diff --git a/backend/src/net/keys.rs b/core/startos/src/net/keys.rs similarity index 100% rename from backend/src/net/keys.rs rename to core/startos/src/net/keys.rs diff --git a/backend/src/net/mdns.rs b/core/startos/src/net/mdns.rs similarity index 100% rename from backend/src/net/mdns.rs rename to core/startos/src/net/mdns.rs diff --git a/backend/src/net/mod.rs b/core/startos/src/net/mod.rs similarity index 100% rename from backend/src/net/mod.rs rename to core/startos/src/net/mod.rs diff --git a/backend/src/net/net_controller.rs b/core/startos/src/net/net_controller.rs similarity index 100% rename from backend/src/net/net_controller.rs rename to core/startos/src/net/net_controller.rs diff --git a/backend/src/net/ssl.rs b/core/startos/src/net/ssl.rs similarity index 100% rename from backend/src/net/ssl.rs rename to core/startos/src/net/ssl.rs diff --git a/backend/src/net/static_server.rs b/core/startos/src/net/static_server.rs similarity index 99% rename from backend/src/net/static_server.rs rename to core/startos/src/net/static_server.rs index a8fe3749e..c4dca85f2 100644 --- a/backend/src/net/static_server.rs +++ b/core/startos/src/net/static_server.rs @@ -35,7 +35,7 @@ static NOT_FOUND: &[u8] = b"Not Found"; static METHOD_NOT_ALLOWED: &[u8] = b"Method Not Allowed"; static NOT_AUTHORIZED: &[u8] = b"Not Authorized"; -static EMBEDDED_UIS: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../frontend/dist/static"); +static EMBEDDED_UIS: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../../web/dist/static"); const PROXY_STRIP_HEADERS: &[&str] = &["cookie", "host", "origin", "referer", "user-agent"]; diff --git a/backend/src/net/tor.rs b/core/startos/src/net/tor.rs similarity index 99% rename from backend/src/net/tor.rs rename to core/startos/src/net/tor.rs index 9926d3c6c..a00ab9c54 100644 --- a/backend/src/net/tor.rs +++ b/core/startos/src/net/tor.rs @@ -684,6 +684,7 @@ impl TorControl { } #[tokio::test] +#[ignore] async fn test() { let mut conn = torut::control::UnauthenticatedConn::new( TcpStream::connect(SocketAddr::from(([127, 0, 0, 1], 9051))) diff --git a/backend/src/net/utils.rs b/core/startos/src/net/utils.rs similarity index 100% rename from backend/src/net/utils.rs rename to core/startos/src/net/utils.rs diff --git a/backend/src/net/vhost.rs b/core/startos/src/net/vhost.rs similarity index 100% rename from backend/src/net/vhost.rs rename to core/startos/src/net/vhost.rs diff --git a/backend/src/net/web_server.rs b/core/startos/src/net/web_server.rs similarity index 100% rename from backend/src/net/web_server.rs rename to core/startos/src/net/web_server.rs diff --git a/backend/src/net/wifi.rs b/core/startos/src/net/wifi.rs similarity index 100% rename from backend/src/net/wifi.rs rename to core/startos/src/net/wifi.rs diff --git a/backend/src/net/wpa_supplicant.conf.base b/core/startos/src/net/wpa_supplicant.conf.base similarity index 100% rename from backend/src/net/wpa_supplicant.conf.base rename to core/startos/src/net/wpa_supplicant.conf.base diff --git a/backend/src/net/ws_server.rs b/core/startos/src/net/ws_server.rs similarity index 100% rename from backend/src/net/ws_server.rs rename to core/startos/src/net/ws_server.rs diff --git a/backend/src/notifications.rs b/core/startos/src/notifications.rs similarity index 100% rename from backend/src/notifications.rs rename to core/startos/src/notifications.rs diff --git a/backend/src/os_install/fstab.template b/core/startos/src/os_install/fstab.template similarity index 100% rename from backend/src/os_install/fstab.template rename to core/startos/src/os_install/fstab.template diff --git a/backend/src/os_install/gpt.rs b/core/startos/src/os_install/gpt.rs similarity index 100% rename from backend/src/os_install/gpt.rs rename to core/startos/src/os_install/gpt.rs diff --git a/backend/src/os_install/mbr.rs b/core/startos/src/os_install/mbr.rs similarity index 100% rename from backend/src/os_install/mbr.rs rename to core/startos/src/os_install/mbr.rs diff --git a/backend/src/os_install/mod.rs b/core/startos/src/os_install/mod.rs similarity index 100% rename from backend/src/os_install/mod.rs rename to core/startos/src/os_install/mod.rs diff --git a/backend/src/prelude.rs b/core/startos/src/prelude.rs similarity index 86% rename from backend/src/prelude.rs rename to core/startos/src/prelude.rs index ab5de1d38..3f70b7a2b 100644 --- a/backend/src/prelude.rs +++ b/core/startos/src/prelude.rs @@ -1,5 +1,6 @@ pub use color_eyre::eyre::eyre; pub use models::OptionExt; +pub use tracing::instrument; pub use crate::db::prelude::*; pub use crate::ensure_code; diff --git a/backend/src/procedure/build.rs b/core/startos/src/procedure/build.rs similarity index 100% rename from backend/src/procedure/build.rs rename to core/startos/src/procedure/build.rs diff --git a/backend/src/procedure/docker.rs b/core/startos/src/procedure/docker.rs similarity index 99% rename from backend/src/procedure/docker.rs rename to core/startos/src/procedure/docker.rs index 57207d5c9..ad25953a3 100644 --- a/backend/src/procedure/docker.rs +++ b/core/startos/src/procedure/docker.rs @@ -810,7 +810,7 @@ impl LongRunning { pkg_version: &Version, socket_path: &Path, ) -> Result { - const INIT_EXEC: &str = "/start9/bin/embassy_container_init"; + const INIT_EXEC: &str = "/start9/bin/container-init"; const BIND_LOCATION: &str = "/usr/lib/startos/container/"; tracing::trace!("setup_long_running_docker_cmd"); diff --git a/backend/src/procedure/js_scripts.rs b/core/startos/src/procedure/js_scripts.rs similarity index 96% rename from backend/src/procedure/js_scripts.rs rename to core/startos/src/procedure/js_scripts.rs index d7e5ae97f..659e6a62c 100644 --- a/backend/src/procedure/js_scripts.rs +++ b/core/startos/src/procedure/js_scripts.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use std::time::Duration; -use embassy_container_init::ProcessGroupId; +use container_init::ProcessGroupId; use helpers::UnixRpcClient; pub use js_engine::JsError; use js_engine::{JsExecutionEnvironment, PathForVolumeId}; @@ -81,8 +81,12 @@ impl JsProcedure { _gid: ProcessGroupId, _rpc_client: Option>, ) -> Result, Error> { - Command::new("start-deno") - .arg("execute") + #[cfg(not(test))] + let mut cmd = Command::new("start-deno"); + #[cfg(test)] + let mut cmd = test_start_deno_command().await?; + + cmd.arg("execute") .input(Some(&mut std::io::Cursor::new(IoFormat::Json.to_vec( &ExecuteArgs { procedure: self.clone(), @@ -111,8 +115,12 @@ impl JsProcedure { timeout: Option, name: ProcedureName, ) -> Result, Error> { - Command::new("start-deno") - .arg("sandbox") + #[cfg(not(test))] + let mut cmd = Command::new("start-deno"); + #[cfg(test)] + let mut cmd = test_start_deno_command().await?; + + cmd.arg("sandbox") .input(Some(&mut std::io::Cursor::new(IoFormat::Json.to_vec( &ExecuteArgs { procedure: self.clone(), @@ -212,6 +220,25 @@ fn unwrap_known_error( } } +async fn test_start_deno_command() -> Result { + Command::new("cargo") + .arg("build") + .invoke(ErrorKind::Unknown) + .await?; + if tokio::fs::metadata("target/debug/start-deno") + .await + .is_err() + { + Command::new("ln") + .arg("-rsf") + .arg("target/debug/startbox") + .arg("target/debug/start-deno") + .invoke(crate::ErrorKind::Filesystem) + .await?; + } + Ok(Command::new("target/debug/start-deno")) +} + #[cfg(test)] mod tests { use super::*; diff --git a/backend/src/procedure/mod.rs b/core/startos/src/procedure/mod.rs similarity index 94% rename from backend/src/procedure/mod.rs rename to core/startos/src/procedure/mod.rs index 5af047e71..f7cccd689 100644 --- a/backend/src/procedure/mod.rs +++ b/core/startos/src/procedure/mod.rs @@ -17,7 +17,7 @@ use crate::volume::Volumes; use crate::{Error, ErrorKind}; pub mod docker; -#[cfg(feature = "js_engine")] +#[cfg(feature = "js-engine")] pub mod js_scripts; pub use models::ProcedureName; @@ -28,14 +28,14 @@ pub use models::ProcedureName; pub enum PackageProcedure { Docker(DockerProcedure), - #[cfg(feature = "js_engine")] + #[cfg(feature = "js-engine")] Script(js_scripts::JsProcedure), } impl PackageProcedure { pub fn is_script(&self) -> bool { match self { - #[cfg(feature = "js_engine")] + #[cfg(feature = "js-engine")] Self::Script(_) => true, _ => false, } @@ -52,7 +52,7 @@ impl PackageProcedure { PackageProcedure::Docker(action) => { action.validate(eos_version, volumes, image_ids, expected_io) } - #[cfg(feature = "js_engine")] + #[cfg(feature = "js-engine")] PackageProcedure::Script(action) => action.validate(volumes), } } @@ -80,7 +80,7 @@ impl PackageProcedure { .execute(ctx, pkg_id, pkg_version, name, volumes, input, timeout) .await } - #[cfg(feature = "js_engine")] + #[cfg(feature = "js-engine")] PackageProcedure::Script(procedure) => { let man = ctx .managers @@ -135,7 +135,7 @@ impl PackageProcedure { .sandboxed(ctx, pkg_id, pkg_version, volumes, input, timeout) .await } - #[cfg(feature = "js_engine")] + #[cfg(feature = "js-engine")] PackageProcedure::Script(procedure) => { procedure .sandboxed( @@ -157,7 +157,7 @@ impl std::fmt::Display for PackageProcedure { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { PackageProcedure::Docker(_) => write!(f, "Docker")?, - #[cfg(feature = "js_engine")] + #[cfg(feature = "js-engine")] PackageProcedure::Script(_) => write!(f, "JS")?, } Ok(()) @@ -180,5 +180,7 @@ impl<'de> Deserialize<'de> for NoOutput { #[test] fn test_deser_no_output() { serde_json::from_str::("").unwrap(); - serde_json::from_str::>("{\"Ok\": null}").unwrap(); + serde_json::from_str::>("{\"Ok\": null}") + .unwrap() + .unwrap(); } diff --git a/backend/src/properties.rs b/core/startos/src/properties.rs similarity index 100% rename from backend/src/properties.rs rename to core/startos/src/properties.rs diff --git a/backend/src/registry/admin.rs b/core/startos/src/registry/admin.rs similarity index 100% rename from backend/src/registry/admin.rs rename to core/startos/src/registry/admin.rs diff --git a/backend/src/registry/marketplace.rs b/core/startos/src/registry/marketplace.rs similarity index 100% rename from backend/src/registry/marketplace.rs rename to core/startos/src/registry/marketplace.rs diff --git a/backend/src/registry/mod.rs b/core/startos/src/registry/mod.rs similarity index 100% rename from backend/src/registry/mod.rs rename to core/startos/src/registry/mod.rs diff --git a/core/startos/src/s9pk/builder.rs b/core/startos/src/s9pk/builder.rs new file mode 100644 index 000000000..199742439 --- /dev/null +++ b/core/startos/src/s9pk/builder.rs @@ -0,0 +1,145 @@ +use sha2::{Digest, Sha512}; +use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt, SeekFrom}; +use tracing::instrument; +use typed_builder::TypedBuilder; + +use super::header::{FileSection, Header}; +use super::manifest::Manifest; +use super::SIG_CONTEXT; +use crate::util::io::to_cbor_async_writer; +use crate::util::HashWriter; +use crate::{Error, ResultExt}; + +#[derive(TypedBuilder)] +pub struct S9pkPacker< + 'a, + W: AsyncWriteExt + AsyncSeekExt, + RLicense: AsyncReadExt + Unpin, + RInstructions: AsyncReadExt + Unpin, + RIcon: AsyncReadExt + Unpin, + RDockerImages: AsyncReadExt + Unpin, + RAssets: AsyncReadExt + Unpin, + RScripts: AsyncReadExt + Unpin, +> { + writer: W, + manifest: &'a Manifest, + license: RLicense, + instructions: RInstructions, + icon: RIcon, + docker_images: RDockerImages, + assets: RAssets, + scripts: Option, +} +impl< + 'a, + W: AsyncWriteExt + AsyncSeekExt + Unpin, + RLicense: AsyncReadExt + Unpin, + RInstructions: AsyncReadExt + Unpin, + RIcon: AsyncReadExt + Unpin, + RDockerImages: AsyncReadExt + Unpin, + RAssets: AsyncReadExt + Unpin, + RScripts: AsyncReadExt + Unpin, + > S9pkPacker<'a, W, RLicense, RInstructions, RIcon, RDockerImages, RAssets, RScripts> +{ + /// BLOCKING + #[instrument(skip_all)] + pub async fn pack(mut self, key: &ed25519_dalek::SigningKey) -> Result<(), Error> { + let header_pos = self.writer.stream_position().await?; + if header_pos != 0 { + tracing::warn!("Appending to non-empty file."); + } + let mut header = Header::placeholder(); + header.serialize(&mut self.writer).await.with_ctx(|_| { + ( + crate::ErrorKind::Serialization, + "Writing Placeholder Header", + ) + })?; + let mut position = self.writer.stream_position().await?; + + let mut writer = HashWriter::new(Sha512::new(), &mut self.writer); + // manifest + to_cbor_async_writer(&mut writer, self.manifest).await?; + let new_pos = writer.inner_mut().stream_position().await?; + header.table_of_contents.manifest = FileSection { + position, + length: new_pos - position, + }; + position = new_pos; + // license + tokio::io::copy(&mut self.license, &mut writer) + .await + .with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying License"))?; + let new_pos = writer.inner_mut().stream_position().await?; + header.table_of_contents.license = FileSection { + position, + length: new_pos - position, + }; + position = new_pos; + // instructions + tokio::io::copy(&mut self.instructions, &mut writer) + .await + .with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Instructions"))?; + let new_pos = writer.inner_mut().stream_position().await?; + header.table_of_contents.instructions = FileSection { + position, + length: new_pos - position, + }; + position = new_pos; + // icon + tokio::io::copy(&mut self.icon, &mut writer) + .await + .with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Icon"))?; + let new_pos = writer.inner_mut().stream_position().await?; + header.table_of_contents.icon = FileSection { + position, + length: new_pos - position, + }; + position = new_pos; + // docker_images + tokio::io::copy(&mut self.docker_images, &mut writer) + .await + .with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Docker Images"))?; + let new_pos = writer.inner_mut().stream_position().await?; + header.table_of_contents.docker_images = FileSection { + position, + length: new_pos - position, + }; + position = new_pos; + // assets + tokio::io::copy(&mut self.assets, &mut writer) + .await + .with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Assets"))?; + let new_pos = writer.inner_mut().stream_position().await?; + header.table_of_contents.assets = FileSection { + position, + length: new_pos - position, + }; + position = new_pos; + // scripts + if let Some(mut scripts) = self.scripts { + tokio::io::copy(&mut scripts, &mut writer) + .await + .with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Scripts"))?; + let new_pos = writer.inner_mut().stream_position().await?; + header.table_of_contents.scripts = Some(FileSection { + position, + length: new_pos - position, + }); + position = new_pos; + } + + // header + let (hash, _) = writer.finish(); + self.writer.seek(SeekFrom::Start(header_pos)).await?; + header.pubkey = key.into(); + header.signature = key.sign_prehashed(hash, Some(SIG_CONTEXT))?; + header + .serialize(&mut self.writer) + .await + .with_ctx(|_| (crate::ErrorKind::Serialization, "Writing Header"))?; + self.writer.seek(SeekFrom::Start(position)).await?; + + Ok(()) + } +} diff --git a/core/startos/src/s9pk/docker.rs b/core/startos/src/s9pk/docker.rs new file mode 100644 index 000000000..be93905fb --- /dev/null +++ b/core/startos/src/s9pk/docker.rs @@ -0,0 +1,95 @@ +use std::borrow::Cow; +use std::collections::BTreeSet; +use std::io::SeekFrom; +use std::path::Path; + +use color_eyre::eyre::eyre; +use futures::{FutureExt, TryStreamExt}; +use serde::{Deserialize, Serialize}; +use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt}; +use tokio_tar::{Archive, Entry}; + +use crate::util::io::from_cbor_async_reader; +use crate::{Error, ErrorKind, ARCH}; + +#[derive(Default, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct DockerMultiArch { + pub default: String, + pub available: BTreeSet, +} + +#[pin_project::pin_project(project = DockerReaderProject)] +#[derive(Debug)] +pub enum DockerReader { + SingleArch(#[pin] R), + MultiArch(#[pin] Entry>), +} +impl DockerReader { + pub async fn new(mut rdr: R) -> Result { + let arch = if let Some(multiarch) = tokio_tar::Archive::new(&mut rdr) + .entries()? + .try_filter_map(|e| { + async move { + Ok(if &*e.path()? == Path::new("multiarch.cbor") { + Some(e) + } else { + None + }) + } + .boxed() + }) + .try_next() + .await? + { + let multiarch: DockerMultiArch = from_cbor_async_reader(multiarch).await?; + Some(if multiarch.available.contains(&**ARCH) { + Cow::Borrowed(&**ARCH) + } else { + Cow::Owned(multiarch.default) + }) + } else { + None + }; + rdr.seek(SeekFrom::Start(0)).await?; + if let Some(arch) = arch { + if let Some(image) = tokio_tar::Archive::new(rdr) + .entries()? + .try_filter_map(|e| { + let arch = arch.clone(); + async move { + Ok(if &*e.path()? == Path::new(&format!("{}.tar", arch)) { + Some(e) + } else { + None + }) + } + .boxed() + }) + .try_next() + .await? + { + Ok(Self::MultiArch(image)) + } else { + Err(Error::new( + eyre!("Docker image section does not contain tarball for architecture"), + ErrorKind::ParseS9pk, + )) + } + } else { + Ok(Self::SingleArch(rdr)) + } + } +} +impl AsyncRead for DockerReader { + fn poll_read( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> std::task::Poll> { + match self.project() { + DockerReaderProject::SingleArch(r) => r.poll_read(cx, buf), + DockerReaderProject::MultiArch(r) => r.poll_read(cx, buf), + } + } +} diff --git a/core/startos/src/s9pk/git_hash.rs b/core/startos/src/s9pk/git_hash.rs new file mode 100644 index 000000000..b2990a111 --- /dev/null +++ b/core/startos/src/s9pk/git_hash.rs @@ -0,0 +1,41 @@ +use std::path::Path; + +use crate::Error; + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub struct GitHash(String); + +impl GitHash { + pub async fn from_path(path: impl AsRef) -> Result { + let hash = tokio::process::Command::new("git") + .args(["describe", "--always", "--abbrev=40", "--dirty=-modified"]) + .current_dir(path) + .output() + .await?; + if !hash.status.success() { + return Err(Error::new( + color_eyre::eyre::eyre!("Could not get hash: {}", String::from_utf8(hash.stderr)?), + crate::ErrorKind::Filesystem, + )); + } + Ok(GitHash(String::from_utf8(hash.stdout)?)) + } +} + +impl AsRef for GitHash { + fn as_ref(&self) -> &str { + &self.0 + } +} + +// #[tokio::test] +// async fn test_githash_for_current() { +// let answer: GitHash = GitHash::from_path(std::env::current_dir().unwrap()) +// .await +// .unwrap(); +// let answer_str: &str = answer.as_ref(); +// assert!( +// !answer_str.is_empty(), +// "Should have a hash for this current working" +// ); +// } diff --git a/core/startos/src/s9pk/header.rs b/core/startos/src/s9pk/header.rs new file mode 100644 index 000000000..4f77ad855 --- /dev/null +++ b/core/startos/src/s9pk/header.rs @@ -0,0 +1,187 @@ +use std::collections::BTreeMap; + +use color_eyre::eyre::eyre; +use ed25519_dalek::{Signature, VerifyingKey}; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWriteExt}; + +use crate::Error; + +pub const MAGIC: [u8; 2] = [59, 59]; +pub const VERSION: u8 = 1; + +#[derive(Debug)] +pub struct Header { + pub pubkey: VerifyingKey, + pub signature: Signature, + pub table_of_contents: TableOfContents, +} +impl Header { + pub fn placeholder() -> Self { + Header { + pubkey: VerifyingKey::default(), + signature: Signature::from_bytes(&[0; 64]), + table_of_contents: Default::default(), + } + } + // MUST BE SAME SIZE REGARDLESS OF DATA + pub async fn serialize(&self, mut writer: W) -> std::io::Result<()> { + writer.write_all(&MAGIC).await?; + writer.write_all(&[VERSION]).await?; + writer.write_all(self.pubkey.as_bytes()).await?; + writer.write_all(&self.signature.to_bytes()).await?; + self.table_of_contents.serialize(writer).await?; + Ok(()) + } + pub async fn deserialize(mut reader: R) -> Result { + let mut magic = [0; 2]; + reader.read_exact(&mut magic).await?; + if magic != MAGIC { + return Err(Error::new( + eyre!("Incorrect Magic: {:?}", magic), + crate::ErrorKind::ParseS9pk, + )); + } + let mut version = [0]; + reader.read_exact(&mut version).await?; + if version[0] != VERSION { + return Err(Error::new( + eyre!("Unknown Version: {}", version[0]), + crate::ErrorKind::ParseS9pk, + )); + } + let mut pubkey_bytes = [0; 32]; + reader.read_exact(&mut pubkey_bytes).await?; + let pubkey = VerifyingKey::from_bytes(&pubkey_bytes) + .map_err(|e| Error::new(e, crate::ErrorKind::ParseS9pk))?; + let mut sig_bytes = [0; 64]; + reader.read_exact(&mut sig_bytes).await?; + let signature = Signature::from_bytes(&sig_bytes); + let table_of_contents = TableOfContents::deserialize(reader).await?; + + Ok(Header { + pubkey, + signature, + table_of_contents, + }) + } +} + +#[derive(Debug, Default)] +pub struct TableOfContents { + pub manifest: FileSection, + pub license: FileSection, + pub instructions: FileSection, + pub icon: FileSection, + pub docker_images: FileSection, + pub assets: FileSection, + pub scripts: Option, +} +impl TableOfContents { + pub async fn serialize(&self, mut writer: W) -> std::io::Result<()> { + let len: u32 = ((1 + "manifest".len() + 16) + + (1 + "license".len() + 16) + + (1 + "instructions".len() + 16) + + (1 + "icon".len() + 16) + + (1 + "docker_images".len() + 16) + + (1 + "assets".len() + 16) + + (1 + "scripts".len() + 16)) as u32; + writer.write_all(&u32::to_be_bytes(len)).await?; + self.manifest + .serialize_entry("manifest", &mut writer) + .await?; + self.license.serialize_entry("license", &mut writer).await?; + self.instructions + .serialize_entry("instructions", &mut writer) + .await?; + self.icon.serialize_entry("icon", &mut writer).await?; + self.docker_images + .serialize_entry("docker_images", &mut writer) + .await?; + self.assets.serialize_entry("assets", &mut writer).await?; + self.scripts + .unwrap_or_default() + .serialize_entry("scripts", &mut writer) + .await?; + Ok(()) + } + pub async fn deserialize(mut reader: R) -> std::io::Result { + let mut toc_len = [0; 4]; + reader.read_exact(&mut toc_len).await?; + let toc_len = u32::from_be_bytes(toc_len); + let mut reader = reader.take(toc_len as u64); + let mut table = BTreeMap::new(); + while let Some((label, section)) = FileSection::deserialize_entry(&mut reader).await? { + table.insert(label, section); + } + fn from_table( + table: &BTreeMap, FileSection>, + label: &str, + ) -> std::io::Result { + table.get(label.as_bytes()).copied().ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + format!("Missing Required Label: {}", label), + ) + }) + } + #[allow(dead_code)] + fn as_opt(fs: FileSection) -> Option { + if fs.position | fs.length == 0 { + // 0/0 is not a valid file section + None + } else { + Some(fs) + } + } + Ok(TableOfContents { + manifest: from_table(&table, "manifest")?, + license: from_table(&table, "license")?, + instructions: from_table(&table, "instructions")?, + icon: from_table(&table, "icon")?, + docker_images: from_table(&table, "docker_images")?, + assets: from_table(&table, "assets")?, + scripts: table.get("scripts".as_bytes()).cloned(), + }) + } +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct FileSection { + pub position: u64, + pub length: u64, +} +impl FileSection { + pub async fn serialize_entry( + self, + label: &str, + mut writer: W, + ) -> std::io::Result<()> { + writer.write_all(&[label.len() as u8]).await?; + writer.write_all(label.as_bytes()).await?; + writer.write_all(&u64::to_be_bytes(self.position)).await?; + writer.write_all(&u64::to_be_bytes(self.length)).await?; + Ok(()) + } + pub async fn deserialize_entry( + mut reader: R, + ) -> std::io::Result, Self)>> { + let mut label_len = [0]; + let read = reader.read(&mut label_len).await?; + if read == 0 { + return Ok(None); + } + let mut label = vec![0; label_len[0] as usize]; + reader.read_exact(&mut label).await?; + let mut pos = [0; 8]; + reader.read_exact(&mut pos).await?; + let mut len = [0; 8]; + reader.read_exact(&mut len).await?; + Ok(Some(( + label, + FileSection { + position: u64::from_be_bytes(pos), + length: u64::from_be_bytes(len), + }, + ))) + } +} diff --git a/core/startos/src/s9pk/manifest.rs b/core/startos/src/s9pk/manifest.rs new file mode 100644 index 000000000..3eee540ed --- /dev/null +++ b/core/startos/src/s9pk/manifest.rs @@ -0,0 +1,211 @@ +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::eyre; +pub use models::PackageId; +use serde::{Deserialize, Serialize}; +use url::Url; + +use super::git_hash::GitHash; +use crate::action::Actions; +use crate::backup::BackupActions; +use crate::config::action::ConfigActions; +use crate::dependencies::Dependencies; +use crate::migration::Migrations; +use crate::net::interface::Interfaces; +use crate::prelude::*; +use crate::procedure::docker::DockerContainers; +use crate::procedure::PackageProcedure; +use crate::status::health_check::HealthChecks; +use crate::util::serde::Regex; +use crate::util::Version; +use crate::version::{Current, VersionT}; +use crate::volume::Volumes; +use crate::Error; + +fn current_version() -> Version { + Current::new().semver().into() +} + +#[derive(Clone, Debug, Deserialize, Serialize, HasModel)] +#[serde(rename_all = "kebab-case")] +#[model = "Model"] +pub struct Manifest { + #[serde(default = "current_version")] + pub eos_version: Version, + pub id: PackageId, + #[serde(default)] + pub git_hash: Option, + pub title: String, + pub version: Version, + pub description: Description, + #[serde(default)] + pub assets: Assets, + #[serde(default)] + pub build: Option>, + pub release_notes: String, + pub license: String, // type of license + pub wrapper_repo: Url, + pub upstream_repo: Url, + pub support_site: Option, + pub marketing_site: Option, + pub donation_url: Option, + #[serde(default)] + pub alerts: Alerts, + pub main: PackageProcedure, + pub health_checks: HealthChecks, + pub config: Option, + pub properties: Option, + pub volumes: Volumes, + // #[serde(default)] + pub interfaces: Interfaces, + // #[serde(default)] + pub backup: BackupActions, + #[serde(default)] + pub migrations: Migrations, + #[serde(default)] + pub actions: Actions, + // #[serde(default)] + // pub permissions: Permissions, + #[serde(default)] + pub dependencies: Dependencies, + pub containers: Option, + + #[serde(default)] + pub replaces: Vec, + + #[serde(default)] + pub hardware_requirements: HardwareRequirements, +} + +impl Manifest { + pub fn package_procedures(&self) -> impl Iterator { + use std::iter::once; + let main = once(&self.main); + let cfg_get = self.config.as_ref().map(|a| &a.get).into_iter(); + let cfg_set = self.config.as_ref().map(|a| &a.set).into_iter(); + let props = self.properties.iter(); + let backups = vec![&self.backup.create, &self.backup.restore].into_iter(); + let migrations = self + .migrations + .to + .values() + .chain(self.migrations.from.values()); + let actions = self.actions.0.values().map(|a| &a.implementation); + main.chain(cfg_get) + .chain(cfg_set) + .chain(props) + .chain(backups) + .chain(migrations) + .chain(actions) + } + + pub fn with_git_hash(mut self, git_hash: GitHash) -> Self { + self.git_hash = Some(git_hash); + self + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct HardwareRequirements { + #[serde(default)] + device: BTreeMap, + ram: Option, + pub arch: Option>, +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct Assets { + #[serde(default)] + pub license: Option, + #[serde(default)] + pub instructions: Option, + #[serde(default)] + pub icon: Option, + #[serde(default)] + pub docker_images: Option, + #[serde(default)] + pub assets: Option, + #[serde(default)] + pub scripts: Option, +} +impl Assets { + pub fn license_path(&self) -> &Path { + self.license + .as_ref() + .map(|a| a.as_path()) + .unwrap_or(Path::new("LICENSE.md")) + } + pub fn instructions_path(&self) -> &Path { + self.instructions + .as_ref() + .map(|a| a.as_path()) + .unwrap_or(Path::new("INSTRUCTIONS.md")) + } + pub fn icon_path(&self) -> &Path { + self.icon + .as_ref() + .map(|a| a.as_path()) + .unwrap_or(Path::new("icon.png")) + } + pub fn icon_type(&self) -> &str { + self.icon + .as_ref() + .and_then(|icon| icon.extension()) + .and_then(|ext| ext.to_str()) + .unwrap_or("png") + } + pub fn docker_images_path(&self) -> &Path { + self.docker_images + .as_ref() + .map(|a| a.as_path()) + .unwrap_or(Path::new("docker-images")) + } + pub fn assets_path(&self) -> &Path { + self.assets + .as_ref() + .map(|a| a.as_path()) + .unwrap_or(Path::new("assets")) + } + pub fn scripts_path(&self) -> &Path { + self.scripts + .as_ref() + .map(|a| a.as_path()) + .unwrap_or(Path::new("scripts")) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Description { + pub short: String, + pub long: String, +} +impl Description { + pub fn validate(&self) -> Result<(), Error> { + if self.short.chars().skip(160).next().is_some() { + return Err(Error::new( + eyre!("Short description must be 160 characters or less."), + crate::ErrorKind::ValidateS9pk, + )); + } + if self.long.chars().skip(5000).next().is_some() { + return Err(Error::new( + eyre!("Long description must be 5000 characters or less."), + crate::ErrorKind::ValidateS9pk, + )); + } + Ok(()) + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct Alerts { + pub install: Option, + pub uninstall: Option, + pub restore: Option, + pub start: Option, + pub stop: Option, +} diff --git a/core/startos/src/s9pk/mod.rs b/core/startos/src/s9pk/mod.rs new file mode 100644 index 000000000..6720f2999 --- /dev/null +++ b/core/startos/src/s9pk/mod.rs @@ -0,0 +1,5 @@ +pub mod merkle_archive; +pub mod v1; +pub mod v2; + +pub use v1::*; diff --git a/core/startos/src/s9pk/reader.rs b/core/startos/src/s9pk/reader.rs new file mode 100644 index 000000000..61b5e46a8 --- /dev/null +++ b/core/startos/src/s9pk/reader.rs @@ -0,0 +1,406 @@ +use std::collections::BTreeSet; +use std::io::SeekFrom; +use std::ops::Range; +use std::path::Path; +use std::pin::Pin; +use std::str::FromStr; +use std::task::{Context, Poll}; + +use color_eyre::eyre::eyre; +use digest::Output; +use ed25519_dalek::VerifyingKey; +use futures::TryStreamExt; +use models::ImageId; +use sha2::{Digest, Sha512}; +use tokio::fs::File; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, ReadBuf}; +use tracing::instrument; + +use super::header::{FileSection, Header, TableOfContents}; +use super::manifest::{Manifest, PackageId}; +use super::SIG_CONTEXT; +use crate::install::progress::InstallProgressTracker; +use crate::s9pk::docker::DockerReader; +use crate::util::Version; +use crate::{Error, ResultExt}; + +const MAX_REPLACES: usize = 10; +const MAX_TITLE_LEN: usize = 30; + +#[pin_project::pin_project] +#[derive(Debug)] +pub struct ReadHandle<'a, R = File> { + pos: &'a mut u64, + range: Range, + #[pin] + rdr: &'a mut R, +} +impl<'a, R: AsyncRead + Unpin> ReadHandle<'a, R> { + pub async fn to_vec(mut self) -> std::io::Result> { + let mut buf = vec![0; (self.range.end - self.range.start) as usize]; + self.read_exact(&mut buf).await?; + Ok(buf) + } +} +impl<'a, R: AsyncRead + Unpin> AsyncRead for ReadHandle<'a, R> { + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + let this = self.project(); + let start = buf.filled().len(); + let mut take_buf = buf.take(this.range.end.saturating_sub(**this.pos) as usize); + let res = AsyncRead::poll_read(this.rdr, cx, &mut take_buf); + let n = take_buf.filled().len(); + unsafe { buf.assume_init(start + n) }; + buf.advance(n); + **this.pos += n as u64; + res + } +} +impl<'a, R: AsyncSeek + Unpin> AsyncSeek for ReadHandle<'a, R> { + fn start_seek(self: Pin<&mut Self>, position: SeekFrom) -> std::io::Result<()> { + let this = self.project(); + AsyncSeek::start_seek( + this.rdr, + match position { + SeekFrom::Current(n) => SeekFrom::Current(n), + SeekFrom::End(n) => SeekFrom::Start((this.range.end as i64 + n) as u64), + SeekFrom::Start(n) => SeekFrom::Start(this.range.start + n), + }, + ) + } + fn poll_complete(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.project(); + match AsyncSeek::poll_complete(this.rdr, cx) { + Poll::Ready(Ok(n)) => { + let res = n.saturating_sub(this.range.start); + **this.pos = this.range.start + res; + Poll::Ready(Ok(res)) + } + a => a, + } + } +} + +#[derive(Debug)] +pub struct ImageTag { + pub package_id: PackageId, + pub image_id: ImageId, + pub version: Version, +} +impl ImageTag { + #[instrument(skip_all)] + pub fn validate(&self, id: &PackageId, version: &Version) -> Result<(), Error> { + if id != &self.package_id { + return Err(Error::new( + eyre!( + "Contains image for incorrect package: id {}", + self.package_id, + ), + crate::ErrorKind::ValidateS9pk, + )); + } + if version != &self.version { + return Err(Error::new( + eyre!( + "Contains image with incorrect version: expected {} received {}", + version, + self.version, + ), + crate::ErrorKind::ValidateS9pk, + )); + } + Ok(()) + } +} +impl FromStr for ImageTag { + type Err = Error; + fn from_str(s: &str) -> Result { + let rest = s.strip_prefix("start9/").ok_or_else(|| { + Error::new( + eyre!("Invalid image tag prefix: expected start9/"), + crate::ErrorKind::ValidateS9pk, + ) + })?; + let (package, rest) = rest.split_once("/").ok_or_else(|| { + Error::new( + eyre!("Image tag missing image id"), + crate::ErrorKind::ValidateS9pk, + ) + })?; + let (image, version) = rest.split_once(":").ok_or_else(|| { + Error::new( + eyre!("Image tag missing version"), + crate::ErrorKind::ValidateS9pk, + ) + })?; + Ok(ImageTag { + package_id: package.parse()?, + image_id: image.parse()?, + version: version.parse()?, + }) + } +} + +pub struct S9pkReader { + hash: Option>, + hash_string: Option, + developer_key: VerifyingKey, + toc: TableOfContents, + pos: u64, + rdr: R, +} +impl S9pkReader { + pub async fn open>(path: P, check_sig: bool) -> Result { + let p = path.as_ref(); + let rdr = File::open(p) + .await + .with_ctx(|_| (crate::error::ErrorKind::Filesystem, p.display().to_string()))?; + + Self::from_reader(rdr, check_sig).await + } +} +impl S9pkReader> { + pub fn validated(&mut self) { + self.rdr.validated() + } +} +impl S9pkReader { + #[instrument(skip_all)] + pub async fn validate(&mut self) -> Result<(), Error> { + if self.toc.icon.length > 102_400 { + // 100 KiB + return Err(Error::new( + eyre!("icon must be less than 100KiB"), + crate::ErrorKind::ValidateS9pk, + )); + } + let image_tags = self.image_tags().await?; + let man = self.manifest().await?; + let containers = &man.containers; + let validated_image_ids = image_tags + .into_iter() + .map(|i| i.validate(&man.id, &man.version).map(|_| i.image_id)) + .collect::, _>>()?; + man.description.validate()?; + man.actions.0.iter().try_for_each(|(_, action)| { + action.validate( + containers, + &man.eos_version, + &man.volumes, + &validated_image_ids, + ) + })?; + man.backup.validate( + containers, + &man.eos_version, + &man.volumes, + &validated_image_ids, + )?; + if let Some(cfg) = &man.config { + cfg.validate( + containers, + &man.eos_version, + &man.volumes, + &validated_image_ids, + )?; + } + man.health_checks + .validate(&man.eos_version, &man.volumes, &validated_image_ids)?; + man.interfaces.validate()?; + man.main + .validate(&man.eos_version, &man.volumes, &validated_image_ids, false) + .with_ctx(|_| (crate::ErrorKind::ValidateS9pk, "Main"))?; + man.migrations.validate( + containers, + &man.eos_version, + &man.volumes, + &validated_image_ids, + )?; + + #[cfg(feature = "js-engine")] + if man.containers.is_some() + || matches!(man.main, crate::procedure::PackageProcedure::Script(_)) + { + return Err(Error::new( + eyre!("Right now we don't support the containers and the long running main"), + crate::ErrorKind::ValidateS9pk, + )); + } + + if man.replaces.len() >= MAX_REPLACES { + return Err(Error::new( + eyre!("Cannot have more than {MAX_REPLACES} replaces"), + crate::ErrorKind::ValidateS9pk, + )); + } + if let Some(too_big) = man.replaces.iter().find(|x| x.len() >= MAX_REPLACES) { + return Err(Error::new( + eyre!("We have found a replaces of ({too_big}) that exceeds the max length of {MAX_TITLE_LEN} "), + crate::ErrorKind::ValidateS9pk, + )); + } + if man.title.len() >= MAX_TITLE_LEN { + return Err(Error::new( + eyre!("Cannot have more than a length of {MAX_TITLE_LEN} for title"), + crate::ErrorKind::ValidateS9pk, + )); + } + + if man.containers.is_some() + && matches!(man.main, crate::procedure::PackageProcedure::Docker(_)) + { + return Err(Error::new( + eyre!("Cannot have a main docker and a main in containers"), + crate::ErrorKind::ValidateS9pk, + )); + } + if let Some(props) = &man.properties { + props + .validate(&man.eos_version, &man.volumes, &validated_image_ids, true) + .with_ctx(|_| (crate::ErrorKind::ValidateS9pk, "Properties"))?; + } + man.volumes.validate(&man.interfaces)?; + + Ok(()) + } + #[instrument(skip_all)] + pub async fn image_tags(&mut self) -> Result, Error> { + let mut tar = tokio_tar::Archive::new(self.docker_images().await?); + let mut entries = tar.entries()?; + while let Some(mut entry) = entries.try_next().await? { + if &*entry.path()? != Path::new("manifest.json") { + continue; + } + let mut buf = Vec::with_capacity(entry.header().size()? as usize); + entry.read_to_end(&mut buf).await?; + #[derive(serde::Deserialize)] + struct ManEntry { + #[serde(rename = "RepoTags")] + tags: Vec, + } + let man_entries = serde_json::from_slice::>(&buf) + .with_ctx(|_| (crate::ErrorKind::Deserialization, "manifest.json"))?; + return man_entries + .iter() + .flat_map(|e| &e.tags) + .map(|t| t.parse()) + .collect(); + } + Err(Error::new( + eyre!("image.tar missing manifest.json"), + crate::ErrorKind::ParseS9pk, + )) + } + #[instrument(skip_all)] + pub async fn from_reader(mut rdr: R, check_sig: bool) -> Result { + let header = Header::deserialize(&mut rdr).await?; + + let (hash, hash_string) = if check_sig { + let mut hasher = Sha512::new(); + let mut buf = [0; 1024]; + let mut read; + while { + read = rdr.read(&mut buf).await?; + read != 0 + } { + hasher.update(&buf[0..read]); + } + let hash = hasher.clone().finalize(); + header + .pubkey + .verify_prehashed(hasher, Some(SIG_CONTEXT), &header.signature)?; + ( + Some(hash), + Some(base32::encode( + base32::Alphabet::RFC4648 { padding: false }, + hash.as_slice(), + )), + ) + } else { + (None, None) + }; + + let pos = rdr.stream_position().await?; + + Ok(S9pkReader { + hash_string, + hash, + developer_key: header.pubkey, + toc: header.table_of_contents, + pos, + rdr, + }) + } + + pub fn hash(&self) -> Option<&Output> { + self.hash.as_ref() + } + + pub fn hash_str(&self) -> Option<&str> { + self.hash_string.as_ref().map(|s| s.as_str()) + } + + pub fn developer_key(&self) -> &VerifyingKey { + &self.developer_key + } + + pub async fn reset(&mut self) -> Result<(), Error> { + self.rdr.seek(SeekFrom::Start(0)).await?; + Ok(()) + } + + async fn read_handle<'a>( + &'a mut self, + section: FileSection, + ) -> Result, Error> { + if self.pos != section.position { + self.rdr.seek(SeekFrom::Start(section.position)).await?; + self.pos = section.position; + } + Ok(ReadHandle { + range: self.pos..(self.pos + section.length), + pos: &mut self.pos, + rdr: &mut self.rdr, + }) + } + + pub async fn manifest_raw(&mut self) -> Result, Error> { + self.read_handle(self.toc.manifest).await + } + + pub async fn manifest(&mut self) -> Result { + let slice = self.manifest_raw().await?.to_vec().await?; + serde_cbor::de::from_reader(slice.as_slice()) + .with_ctx(|_| (crate::ErrorKind::ParseS9pk, "Deserializing Manifest (CBOR)")) + } + + pub async fn license(&mut self) -> Result, Error> { + self.read_handle(self.toc.license).await + } + + pub async fn instructions(&mut self) -> Result, Error> { + self.read_handle(self.toc.instructions).await + } + + pub async fn icon(&mut self) -> Result, Error> { + self.read_handle(self.toc.icon).await + } + + pub async fn docker_images(&mut self) -> Result>, Error> { + DockerReader::new(self.read_handle(self.toc.docker_images).await?).await + } + + pub async fn assets(&mut self) -> Result, Error> { + self.read_handle(self.toc.assets).await + } + + pub async fn scripts(&mut self) -> Result>, Error> { + Ok(match self.toc.scripts { + None => None, + Some(a) => Some(self.read_handle(a).await?), + }) + } +} diff --git a/backend/src/s9pk/specv2.md b/core/startos/src/s9pk/specv2.md similarity index 100% rename from backend/src/s9pk/specv2.md rename to core/startos/src/s9pk/specv2.md diff --git a/backend/src/setup.rs b/core/startos/src/setup.rs similarity index 100% rename from backend/src/setup.rs rename to core/startos/src/setup.rs diff --git a/backend/src/shutdown.rs b/core/startos/src/shutdown.rs similarity index 100% rename from backend/src/shutdown.rs rename to core/startos/src/shutdown.rs diff --git a/backend/src/sound.rs b/core/startos/src/sound.rs similarity index 100% rename from backend/src/sound.rs rename to core/startos/src/sound.rs diff --git a/backend/src/ssh.rs b/core/startos/src/ssh.rs similarity index 100% rename from backend/src/ssh.rs rename to core/startos/src/ssh.rs diff --git a/backend/src/status/health_check.rs b/core/startos/src/status/health_check.rs similarity index 100% rename from backend/src/status/health_check.rs rename to core/startos/src/status/health_check.rs diff --git a/backend/src/status/mod.rs b/core/startos/src/status/mod.rs similarity index 100% rename from backend/src/status/mod.rs rename to core/startos/src/status/mod.rs diff --git a/backend/src/system.rs b/core/startos/src/system.rs similarity index 99% rename from backend/src/system.rs rename to core/startos/src/system.rs index 989cdc4aa..53216f796 100644 --- a/backend/src/system.rs +++ b/core/startos/src/system.rs @@ -841,6 +841,7 @@ async fn get_disk_info() -> Result { } #[tokio::test] +#[ignore] pub async fn test_get_temp() { println!("{}", get_temp().await.unwrap()) } @@ -856,6 +857,7 @@ pub async fn test_get_mem_info() { } #[tokio::test] +#[ignore] pub async fn test_get_disk_usage() { println!("{:?}", get_disk_info().await.unwrap()) } diff --git a/backend/src/update/latest_information.rs b/core/startos/src/update/latest_information.rs similarity index 100% rename from backend/src/update/latest_information.rs rename to core/startos/src/update/latest_information.rs diff --git a/backend/src/update/mod.rs b/core/startos/src/update/mod.rs similarity index 100% rename from backend/src/update/mod.rs rename to core/startos/src/update/mod.rs diff --git a/backend/src/util/config.rs b/core/startos/src/util/config.rs similarity index 100% rename from backend/src/util/config.rs rename to core/startos/src/util/config.rs diff --git a/backend/src/util/cpupower.rs b/core/startos/src/util/cpupower.rs similarity index 100% rename from backend/src/util/cpupower.rs rename to core/startos/src/util/cpupower.rs diff --git a/backend/src/util/crypto.rs b/core/startos/src/util/crypto.rs similarity index 100% rename from backend/src/util/crypto.rs rename to core/startos/src/util/crypto.rs diff --git a/backend/src/util/docker.rs b/core/startos/src/util/docker.rs similarity index 100% rename from backend/src/util/docker.rs rename to core/startos/src/util/docker.rs diff --git a/backend/src/util/http_reader.rs b/core/startos/src/util/http_reader.rs similarity index 100% rename from backend/src/util/http_reader.rs rename to core/startos/src/util/http_reader.rs diff --git a/backend/src/util/io.rs b/core/startos/src/util/io.rs similarity index 100% rename from backend/src/util/io.rs rename to core/startos/src/util/io.rs diff --git a/backend/src/util/logger.rs b/core/startos/src/util/logger.rs similarity index 100% rename from backend/src/util/logger.rs rename to core/startos/src/util/logger.rs diff --git a/backend/src/util/lshw.rs b/core/startos/src/util/lshw.rs similarity index 100% rename from backend/src/util/lshw.rs rename to core/startos/src/util/lshw.rs diff --git a/backend/src/util/mod.rs b/core/startos/src/util/mod.rs similarity index 96% rename from backend/src/util/mod.rs rename to core/startos/src/util/mod.rs index 2683f23c8..34c05934b 100644 --- a/backend/src/util/mod.rs +++ b/core/startos/src/util/mod.rs @@ -466,3 +466,27 @@ impl FileLock { pub fn assure_send(x: T) -> T { x } + +pub enum MaybeOwned<'a, T> { + Borrowed(&'a T), + Owned(T), +} +impl<'a, T> std::ops::Deref for MaybeOwned<'a, T> { + type Target = T; + fn deref(&self) -> &Self::Target { + match self { + Self::Borrowed(a) => *a, + Self::Owned(a) => a, + } + } +} +impl<'a, T> From for MaybeOwned<'a, T> { + fn from(value: T) -> Self { + MaybeOwned::Owned(value) + } +} +impl<'a, T> From<&'a T> for MaybeOwned<'a, T> { + fn from(value: &'a T) -> Self { + MaybeOwned::Borrowed(value) + } +} diff --git a/backend/src/util/serde.rs b/core/startos/src/util/serde.rs similarity index 100% rename from backend/src/util/serde.rs rename to core/startos/src/util/serde.rs diff --git a/backend/src/version/mod.rs b/core/startos/src/version/mod.rs similarity index 98% rename from backend/src/version/mod.rs rename to core/startos/src/version/mod.rs index 3c14c934d..a9d91cf73 100644 --- a/backend/src/version/mod.rs +++ b/core/startos/src/version/mod.rs @@ -200,7 +200,8 @@ pub async fn init(db: &PatchDb, secrets: &PgPool) -> Result<(), Error> { Ok(()) } -pub const COMMIT_HASH: &str = include_str!("../../../GIT_HASH.txt"); +pub const COMMIT_HASH: &str = + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../GIT_HASH.txt")); #[command(rename = "git-info", local, metadata(authenticated = false))] pub fn git_info() -> Result<&'static str, Error> { diff --git a/core/startos/src/version/v0_3_4.rs b/core/startos/src/version/v0_3_4.rs new file mode 100644 index 000000000..e33dcb931 --- /dev/null +++ b/core/startos/src/version/v0_3_4.rs @@ -0,0 +1,135 @@ +use async_trait::async_trait; +use emver::VersionRange; +use itertools::Itertools; +use openssl::hash::MessageDigest; +use serde_json::json; +use ssh_key::public::Ed25519PublicKey; + +use super::*; +use crate::account::AccountInfo; +use crate::hostname::{sync_hostname, Hostname}; +use crate::prelude::*; + +const V0_3_4: emver::Version = emver::Version::new(0, 3, 4, 0); + +lazy_static::lazy_static! { + pub static ref V0_3_0_COMPAT: VersionRange = VersionRange::Conj( + Box::new(VersionRange::Anchor( + emver::GTE, + emver::Version::new(0, 3, 0, 0), + )), + Box::new(VersionRange::Anchor(emver::LTE, Current::new().semver())), + ); +} + +const COMMUNITY_URL: &str = "https://community-registry.start9.com/"; +const MAIN_REGISTRY: &str = "https://registry.start9.com/"; +const COMMUNITY_SERVICES: &[&str] = &[ + "ipfs", + "agora", + "lightning-jet", + "balanceofsatoshis", + "mastodon", + "lndg", + "robosats", + "thunderhub", + "syncthing", + "sphinx-relay", +]; + +#[derive(Clone, Debug)] +pub struct Version; + +#[async_trait] +impl VersionT for Version { + type Previous = Self; + fn new() -> Self { + Version + } + fn semver(&self) -> emver::Version { + V0_3_4 + } + fn compat(&self) -> &'static VersionRange { + &*V0_3_0_COMPAT + } + async fn up(&self, db: PatchDb, secrets: &PgPool) -> Result<(), Error> { + let mut account = AccountInfo::load(secrets).await?; + let account = db + .mutate(|d| { + d.as_server_info_mut().as_pubkey_mut().ser( + &ssh_key::PublicKey::from(Ed25519PublicKey::from(&account.key.ssh_key())) + .to_openssh()?, + )?; + d.as_server_info_mut().as_ca_fingerprint_mut().ser( + &account + .root_ca_cert + .digest(MessageDigest::sha256()) + .unwrap() + .iter() + .map(|x| format!("{x:X}")) + .join(":"), + )?; + let server_info = d.as_server_info(); + account.hostname = server_info.as_hostname().de().map(Hostname)?; + account.server_id = server_info.as_id().de()?; + + Ok(account) + }) + .await?; + account.save(secrets).await?; + sync_hostname(&account.hostname).await?; + + let parsed_url = Some(COMMUNITY_URL.parse().unwrap()); + db.mutate(|d| { + let mut ui = d.as_ui().de()?; + use imbl_value::json; + ui["marketplace"]["known-hosts"][COMMUNITY_URL] = json!({}); + ui["marketplace"]["known-hosts"][MAIN_REGISTRY] = json!({}); + for package_id in d.as_package_data().keys()? { + if !COMMUNITY_SERVICES.contains(&&*package_id.to_string()) { + continue; + } + d.as_package_data_mut() + .as_idx_mut(&package_id) + .or_not_found(&package_id)? + .as_installed_mut() + .or_not_found(&package_id)? + .as_marketplace_url_mut() + .ser(&parsed_url)?; + } + ui["theme"] = json!("Dark".to_string()); + ui["widgets"] = json!([]); + + d.as_ui_mut().ser(&ui) + }) + .await + } + async fn down(&self, db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + db.mutate(|d| { + let mut ui = d.as_ui().de()?; + let parsed_url = Some(MAIN_REGISTRY.parse().unwrap()); + for package_id in d.as_package_data().keys()? { + if !COMMUNITY_SERVICES.contains(&&*package_id.to_string()) { + continue; + } + d.as_package_data_mut() + .as_idx_mut(&package_id) + .or_not_found(&package_id)? + .as_installed_mut() + .or_not_found(&package_id)? + .as_marketplace_url_mut() + .ser(&parsed_url)?; + } + + if let imbl_value::Value::Object(ref mut obj) = ui { + obj.remove("theme"); + obj.remove("widgets"); + } + + ui["marketplace"]["known-hosts"][COMMUNITY_URL].take(); + ui["marketplace"]["known-hosts"][MAIN_REGISTRY].take(); + d.as_ui_mut().ser(&ui) + }) + .await + } +} diff --git a/core/startos/src/version/v0_3_4_1.rs b/core/startos/src/version/v0_3_4_1.rs new file mode 100644 index 000000000..915a47235 --- /dev/null +++ b/core/startos/src/version/v0_3_4_1.rs @@ -0,0 +1,31 @@ +use async_trait::async_trait; +use emver::VersionRange; + +use super::v0_3_4::V0_3_0_COMPAT; +use super::*; +use crate::prelude::*; + +const V0_3_4_1: emver::Version = emver::Version::new(0, 3, 4, 1); + +#[derive(Clone, Debug)] +pub struct Version; + +#[async_trait] +impl VersionT for Version { + type Previous = v0_3_4::Version; + fn new() -> Self { + Version + } + fn semver(&self) -> emver::Version { + V0_3_4_1 + } + fn compat(&self) -> &'static VersionRange { + &*V0_3_0_COMPAT + } + async fn up(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + Ok(()) + } + async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + Ok(()) + } +} diff --git a/core/startos/src/version/v0_3_4_2.rs b/core/startos/src/version/v0_3_4_2.rs new file mode 100644 index 000000000..5931b2879 --- /dev/null +++ b/core/startos/src/version/v0_3_4_2.rs @@ -0,0 +1,31 @@ +use async_trait::async_trait; +use emver::VersionRange; + +use super::v0_3_4::V0_3_0_COMPAT; +use super::*; +use crate::prelude::*; + +const V0_3_4_2: emver::Version = emver::Version::new(0, 3, 4, 2); + +#[derive(Clone, Debug)] +pub struct Version; + +#[async_trait] +impl VersionT for Version { + type Previous = v0_3_4_1::Version; + fn new() -> Self { + Version + } + fn semver(&self) -> emver::Version { + V0_3_4_2 + } + fn compat(&self) -> &'static VersionRange { + &*V0_3_0_COMPAT + } + async fn up(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + Ok(()) + } + async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + Ok(()) + } +} diff --git a/core/startos/src/version/v0_3_4_3.rs b/core/startos/src/version/v0_3_4_3.rs new file mode 100644 index 000000000..d3199e913 --- /dev/null +++ b/core/startos/src/version/v0_3_4_3.rs @@ -0,0 +1,31 @@ +use async_trait::async_trait; +use emver::VersionRange; + +use super::v0_3_4::V0_3_0_COMPAT; +use super::*; +use crate::prelude::*; + +const V0_3_4_3: emver::Version = emver::Version::new(0, 3, 4, 3); + +#[derive(Clone, Debug)] +pub struct Version; + +#[async_trait] +impl VersionT for Version { + type Previous = v0_3_4_2::Version; + fn new() -> Self { + Version + } + fn semver(&self) -> emver::Version { + V0_3_4_3 + } + fn compat(&self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + async fn up(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + Ok(()) + } + async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + Ok(()) + } +} diff --git a/core/startos/src/version/v0_3_4_4.rs b/core/startos/src/version/v0_3_4_4.rs new file mode 100644 index 000000000..b6345ca4c --- /dev/null +++ b/core/startos/src/version/v0_3_4_4.rs @@ -0,0 +1,43 @@ +use async_trait::async_trait; +use emver::VersionRange; +use models::ResultExt; +use sqlx::PgPool; + +use super::v0_3_4::V0_3_0_COMPAT; +use super::{v0_3_4_3, VersionT}; +use crate::prelude::*; + +const V0_3_4_4: emver::Version = emver::Version::new(0, 3, 4, 4); + +#[derive(Clone, Debug)] +pub struct Version; + +#[async_trait] +impl VersionT for Version { + type Previous = v0_3_4_3::Version; + fn new() -> Self { + Version + } + fn semver(&self) -> emver::Version { + V0_3_4_4 + } + fn compat(&self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + async fn up(&self, db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + db.mutate(|v| { + let tor_address_lens = v.as_server_info_mut().as_tor_address_mut(); + let mut tor_addr = tor_address_lens.de()?; + tor_addr + .set_scheme("https") + .map_err(|_| eyre!("unable to update url scheme to https")) + .with_kind(crate::ErrorKind::ParseUrl)?; + tor_address_lens.ser(&tor_addr) + }) + .await?; + Ok(()) + } + async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + Ok(()) + } +} diff --git a/backend/src/version/v0_3_5.rs b/core/startos/src/version/v0_3_5.rs similarity index 100% rename from backend/src/version/v0_3_5.rs rename to core/startos/src/version/v0_3_5.rs diff --git a/backend/src/version/v0_4_0.rs b/core/startos/src/version/v0_4_0.rs similarity index 100% rename from backend/src/version/v0_4_0.rs rename to core/startos/src/version/v0_4_0.rs diff --git a/backend/src/volume.rs b/core/startos/src/volume.rs similarity index 100% rename from backend/src/volume.rs rename to core/startos/src/volume.rs diff --git a/backend/startd.service b/core/startos/startd.service similarity index 100% rename from backend/startd.service rename to core/startos/startd.service diff --git a/backend/test/config-spec/lnd-correct.yaml b/core/startos/test/config-spec/lnd-correct.yaml similarity index 100% rename from backend/test/config-spec/lnd-correct.yaml rename to core/startos/test/config-spec/lnd-correct.yaml diff --git a/backend/test/config-spec/lnd-invalid-regex.yaml b/core/startos/test/config-spec/lnd-invalid-regex.yaml similarity index 100% rename from backend/test/config-spec/lnd-invalid-regex.yaml rename to core/startos/test/config-spec/lnd-invalid-regex.yaml diff --git a/backend/test/config-spec/lnd-missing-pattern-description.yaml b/core/startos/test/config-spec/lnd-missing-pattern-description.yaml similarity index 100% rename from backend/test/config-spec/lnd-missing-pattern-description.yaml rename to core/startos/test/config-spec/lnd-missing-pattern-description.yaml diff --git a/backend/test/config-spec/lnd-missing-pattern.yaml b/core/startos/test/config-spec/lnd-missing-pattern.yaml similarity index 100% rename from backend/test/config-spec/lnd-missing-pattern.yaml rename to core/startos/test/config-spec/lnd-missing-pattern.yaml diff --git a/backend/test/js_action_execute/package-data/scripts/test-package/0.3.0.3/embassy.js b/core/startos/test/js_action_execute/package-data/scripts/test-package/0.3.0.3/embassy.js similarity index 100% rename from backend/test/js_action_execute/package-data/scripts/test-package/0.3.0.3/embassy.js rename to core/startos/test/js_action_execute/package-data/scripts/test-package/0.3.0.3/embassy.js diff --git a/backend/test/js_action_execute/package-data/volumes/test-package/data/bad_file.txt b/core/startos/test/js_action_execute/package-data/volumes/test-package/data/bad_file.txt similarity index 100% rename from backend/test/js_action_execute/package-data/volumes/test-package/data/bad_file.txt rename to core/startos/test/js_action_execute/package-data/volumes/test-package/data/bad_file.txt diff --git a/backend/test/js_action_execute/package-data/volumes/test-package/data/main/hack_back b/core/startos/test/js_action_execute/package-data/volumes/test-package/data/main/hack_back similarity index 100% rename from backend/test/js_action_execute/package-data/volumes/test-package/data/main/hack_back rename to core/startos/test/js_action_execute/package-data/volumes/test-package/data/main/hack_back diff --git a/backend/test/js_action_execute/package-data/volumes/test-package/data/main/testing-rsync/someFile.txt b/core/startos/test/js_action_execute/package-data/volumes/test-package/data/main/testing-rsync/someFile.txt similarity index 100% rename from backend/test/js_action_execute/package-data/volumes/test-package/data/main/testing-rsync/someFile.txt rename to core/startos/test/js_action_execute/package-data/volumes/test-package/data/main/testing-rsync/someFile.txt diff --git a/backend/update-sqlx-data.sh b/core/startos/update-sqlx-data.sh similarity index 100% rename from backend/update-sqlx-data.sh rename to core/startos/update-sqlx-data.sh diff --git a/backend/taplo.toml b/core/taplo.toml similarity index 100% rename from backend/taplo.toml rename to core/taplo.toml diff --git a/frontend/.vscode/extensions.json b/frontend/.vscode/extensions.json deleted file mode 100644 index 77b374577..000000000 --- a/frontend/.vscode/extensions.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 - "recommendations": ["angular.ng-template"] -} diff --git a/frontend/.vscode/launch.json b/frontend/.vscode/launch.json deleted file mode 100644 index 740e35a0c..000000000 --- a/frontend/.vscode/launch.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "ng serve", - "type": "pwa-chrome", - "request": "launch", - "preLaunchTask": "npm: start", - "url": "http://localhost:4200/" - }, - { - "name": "ng test", - "type": "chrome", - "request": "launch", - "preLaunchTask": "npm: test", - "url": "http://localhost:9876/debug.html" - } - ] -} diff --git a/frontend/.vscode/tasks.json b/frontend/.vscode/tasks.json deleted file mode 100644 index a298b5bd8..000000000 --- a/frontend/.vscode/tasks.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "start", - "isBackground": true, - "problemMatcher": { - "owner": "typescript", - "pattern": "$tsc", - "background": { - "activeOnStart": true, - "beginsPattern": { - "regexp": "(.*?)" - }, - "endsPattern": { - "regexp": "bundle generation complete" - } - } - } - }, - { - "type": "npm", - "script": "test", - "isBackground": true, - "problemMatcher": { - "owner": "typescript", - "pattern": "$tsc", - "background": { - "activeOnStart": true, - "beginsPattern": { - "regexp": "(.*?)" - }, - "endsPattern": { - "regexp": "bundle generation complete" - } - } - } - } - ] -} diff --git a/frontend/projects/ui/src/globals.d.ts b/frontend/projects/ui/src/globals.d.ts deleted file mode 100644 index 5172a75b6..000000000 --- a/frontend/projects/ui/src/globals.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '*.md' \ No newline at end of file diff --git a/libs/Cargo.toml b/libs/Cargo.toml deleted file mode 100644 index 907cd1e6a..000000000 --- a/libs/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[workspace] - -members = [ - "snapshot_creator", - "models", - "js_engine", - "helpers", - "embassy_container_init", -] diff --git a/libs/artifacts/types.d.ts b/libs/artifacts/types.d.ts deleted file mode 100644 index ccf7acd42..000000000 --- a/libs/artifacts/types.d.ts +++ /dev/null @@ -1,374 +0,0 @@ -export namespace ExpectedExports { - /** Set configuration is called after we have modified and saved the configuration in the StartOS ui. Use this to make a file for the docker to read from for configuration. */ - export type setConfig = ( - effects: Effects, - input: Config - ) => Promise>; - /** Get configuration returns a shape that describes the format that the StartOS ui will generate, and later send to the set config */ - export type getConfig = (effects: Effects) => Promise>; - /** These are how we make sure the our dependency configurations are valid and if not how to fix them. */ - export type dependencies = Dependencies; - /** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */ - export type properties = ( - effects: Effects - ) => Promise>; - - export type health = { - /** Should be the health check id */ - [id: string]: ( - effects: Effects, - dateMs: number - ) => Promise>; - }; - export type migration = ( - effects: Effects, - version: string - ) => Promise>; -} - -/** Used to reach out from the pure js runtime */ -export type Effects = { - /** Usable when not sandboxed */ - writeFile(input: { - path: string; - volumeId: string; - toWrite: string; - }): Promise; - readFile(input: { volumeId: string; path: string }): Promise; - metadata(input: { volumeId: string; path: string }): Promise; - /** Create a directory. Usable when not sandboxed */ - createDir(input: { volumeId: string; path: string }): Promise; - /** Remove a directory. Usable when not sandboxed */ - removeDir(input: { volumeId: string; path: string }): Promise; - removeFile(input: { volumeId: string; path: string }): Promise; - - /** Write a json file into an object. Usable when not sandboxed */ - writeJsonFile(input: { - volumeId: string; - path: string; - toWrite: object; - }): Promise; - - /** Read a json file into an object */ - readJsonFile(input: { volumeId: string; path: string }): Promise; - - /** Log at the trace level */ - trace(whatToPrint: string): void; - /** Log at the warn level */ - warn(whatToPrint: string): void; - /** Log at the error level */ - error(whatToPrint: string): void; - /** Log at the debug level */ - debug(whatToPrint: string): void; - /** Log at the info level */ - info(whatToPrint: string): void; - - /** Sandbox mode lets us read but not write */ - is_sandboxed(): boolean; -}; -export type Metadata = { - fileType: string; - isDir: boolean; - isFile: boolean; - isSymlink: boolean; - len: number; - modified?: Date; - accessed?: Date; - created?: Date; - readonly: boolean; - uid: number; - gid: number; - mode: number; -}; - -export type MigrationRes = { - configured: boolean; -}; - -export type ActionResult = { - version: "0"; - message: string; - value?: string; - copyable: boolean; - qr: boolean; -}; - -export type ConfigRes = { - /** This should be the previous config, that way during set config we start with the previous */ - config?: Config; - /** Shape that is describing the form in the ui */ - spec: ConfigSpec; -}; -export type Config = { - [propertyName: string]: any; -}; - -export type ConfigSpec = { - /** Given a config value, define what it should render with the following spec */ - [configValue: string]: ValueSpecAny; -}; -export type WithDefault = T & { - default?: Default; -}; - -export type WithDescription = T & { - description?: String; - name: string; - warning?: string; -}; - -export type ListSpec = { - spec: T; - range: string; -}; - -export type Tag = V & { - type: T; -}; - -export type Subtype = V & { - subtype: T; -}; - -export type Target = V & { - target: T; -}; - -export type UniqueBy = - | { - any: UniqueBy[]; - } - | string - | null; - -export type WithNullable = T & { - nullable: boolean; -}; -export type DefaultString = - | String - | { - /** The chars available for the randome generation */ - charset?: string; - /** Length that we generate to */ - len: number; - }; - -export type ValueSpecString = ( - | {} - | { - pattern: string; - "pattern-description": string; - } -) & { - copyable?: boolean; - masked?: boolean; - placeholder?: string; -}; -export type ValueSpecNumber = { - /** Something like [3,6] or [0, *) */ - range?: string; - integral?: boolean; - /** Used a description of the units */ - units?: string; - placeholder?: number; -}; -export type ValueSpecBoolean = {}; -export type ValueSpecAny = - | Tag<"boolean", WithDescription>> - | Tag< - "string", - WithDescription, DefaultString>> - > - | Tag< - "number", - WithDescription, number>> - > - | Tag< - "enum", - WithDescription< - WithDefault< - { - values: string[]; - "value-names": { - [key: string]: string; - }; - }, - string - > - > - > - | Tag<"list", ValueSpecList> - | Tag<"object", WithDescription>> - | Tag<"union", WithDescription>> - | Tag< - "pointer", - WithDescription< - | Subtype< - "package", - | Target< - "tor-key", - { - "package-id": string; - interface: string; - } - > - | Target< - "tor-address", - { - "package-id": string; - interface: string; - } - > - | Target< - "lan-address", - { - "package-id": string; - interface: string; - } - > - | Target< - "config", - { - "package-id": string; - selector: string; - multi: boolean; - } - > - > - | Subtype<"system", {}> - > - >; -export type ValueSpecUnion = { - /** What tag for the specification, for tag unions */ - tag: { - id: string; - name: string; - description?: string; - "variant-names": { - [key: string]: string; - }; - }; - /** The possible enum values */ - variants: { - [key: string]: ConfigSpec; - }; - "display-as"?: string; - "unique-by"?: UniqueBy; -}; -export type ValueSpecObject = { - spec: ConfigSpec; - "display-as"?: string; - "unique-by"?: UniqueBy; -}; -export type ValueSpecList = - | Subtype< - "boolean", - WithDescription, boolean[]>> - > - | Subtype< - "string", - WithDescription, string[]>> - > - | Subtype< - "number", - WithDescription, number[]>> - > - | Subtype< - "enum", - WithDescription, string[]>> - > - | Subtype< - "object", - WithDescription, {}[]>> - > - | Subtype< - "union", - WithDescription, string[]>> - >; -export type ValueSpecEnum = { - values: string[]; - "value-names": { [key: string]: string }; -}; - -export type SetResult = { - /** These are the unix process signals */ - signal: - | "SIGTERM" - | "SIGHUP" - | "SIGINT" - | "SIGQUIT" - | "SIGILL" - | "SIGTRAP" - | "SIGABRT" - | "SIGBUS" - | "SIGFPE" - | "SIGKILL" - | "SIGUSR1" - | "SIGSEGV" - | "SIGUSR2" - | "SIGPIPE" - | "SIGALRM" - | "SIGSTKFLT" - | "SIGCHLD" - | "SIGCONT" - | "SIGSTOP" - | "SIGTSTP" - | "SIGTTIN" - | "SIGTTOU" - | "SIGURG" - | "SIGXCPU" - | "SIGXFSZ" - | "SIGVTALRM" - | "SIGPROF" - | "SIGWINCH" - | "SIGIO" - | "SIGPWR" - | "SIGSYS" - | "SIGEMT" - | "SIGINFO"; - "depends-on": { - [packageId: string]: string[]; - }; -}; - -export type KnownError = - | { error: String } - | { - "error-code": [number, string] | readonly [number, string]; - }; -export type ResultType = KnownError | { result: T }; - -export type PackagePropertiesV2 = { - [name: string]: PackagePropertyObject | PackagePropertyString; -}; -export type PackagePropertyString = { - type: "string"; - description?: string; - value: string; - /** Let's the ui make this copyable button */ - copyable?: boolean; - /** Let the ui create a qr for this field */ - qr?: boolean; - /** Hiding the value unless toggled off for field */ - masked?: boolean; -}; -export type PackagePropertyObject = { - value: PackagePropertiesV2; - type: "object"; - description: string; -}; - -export type Properties = { - version: 2; - data: PackagePropertiesV2; -}; - -export type Dependencies = { - /** Id is the id of the package, should be the same as the manifest */ - [id: string]: { - /** Checks are called to make sure that our dependency is in the correct shape. If a known error is returned we know that the dependency needs modification */ - check(effects: Effects, input: Config): Promise>; - /** This is called after we know that the dependency package needs a new configuration, this would be a transform for defaults */ - autoConfigure(effects: Effects, input: Config): Promise>; - }; -}; diff --git a/libs/build-v8-snapshot.sh b/libs/build-v8-snapshot.sh deleted file mode 100755 index 7715b503a..000000000 --- a/libs/build-v8-snapshot.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# Reason for this being is that we need to create a snapshot for the deno runtime. It wants to pull 3 files from build, and during the creation it gets embedded, but for some -# reason during the actual runtime it is looking for them. So this will create a docker in arm that creates the snaphot needed for the arm -set -e - -if [ "$0" != "./build-v8-snapshot.sh" ]; then - >&2 echo "Must be run from backend/workspace directory" - exit 1 -fi - -echo "Creating v8 Snapshot" -cargo run -p snapshot_creator --release -sudo chown -R $USER target -sudo chown -R $USER ~/.cargo -sudo chown $USER JS_SNAPSHOT.bin -sudo chmod 0644 JS_SNAPSHOT.bin - -sudo mv -f JS_SNAPSHOT.bin ./js_engine/src/artifacts/JS_SNAPSHOT.bin \ No newline at end of file diff --git a/libs/rustfmt.toml b/libs/rustfmt.toml deleted file mode 100644 index 64d94def2..000000000 --- a/libs/rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -group_imports = "StdExternalCrate" -imports_granularity = "Module" diff --git a/system-images/compat/Cargo.lock b/system-images/compat/Cargo.lock index 0b036859d..a431dbeb0 100644 --- a/system-images/compat/Cargo.lock +++ b/system-images/compat/Cargo.lock @@ -683,6 +683,28 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "container-init" +version = "0.1.0" +dependencies = [ + "async-stream", + "color-eyre", + "futures", + "helpers", + "imbl", + "nix 0.27.1", + "procfs", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tracing", + "tracing-error", + "tracing-futures", + "tracing-subscriber", + "yajrc 0.1.0 (git+https://github.com/dr-bonez/yajrc.git?branch=develop)", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -1236,28 +1258,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "embassy_container_init" -version = "0.1.0" -dependencies = [ - "async-stream", - "color-eyre", - "futures", - "helpers", - "imbl", - "nix 0.27.1", - "procfs", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tracing", - "tracing-error", - "tracing-futures", - "tracing-subscriber", - "yajrc 0.1.0 (git+https://github.com/dr-bonez/yajrc.git?branch=develop)", -] - [[package]] name = "emver" version = "0.1.7" @@ -4434,6 +4434,7 @@ dependencies = [ "clap 3.2.25", "color-eyre", "console", + "container-init", "cookie 0.18.0", "cookie_store 0.20.0", "current_platform", @@ -4442,7 +4443,6 @@ dependencies = [ "ed25519 2.2.3", "ed25519-dalek 1.0.1", "ed25519-dalek 2.0.0", - "embassy_container_init", "emver", "fd-lock-rs", "futures", diff --git a/system-images/compat/Cargo.toml b/system-images/compat/Cargo.toml index 199b7e1c5..e527c4150 100644 --- a/system-images/compat/Cargo.toml +++ b/system-images/compat/Cargo.toml @@ -11,7 +11,7 @@ anyhow = { version = "1.0.40", features = ["backtrace"] } beau_collector = "0.2.1" clap = "2.33.3" dashmap = "5.3.2" -start-os = { path = "../../backend", default-features = false } +start-os = { path = "../../core/startos", default-features = false } emver = { version = "0.1.7", git = "https://github.com/Start9Labs/emver-rs.git", features = [ "serde", ] } diff --git a/system-images/compat/Makefile b/system-images/compat/Makefile index f1ba3cd4b..86d881193 100644 --- a/system-images/compat/Makefile +++ b/system-images/compat/Makefile @@ -17,8 +17,8 @@ docker-images/aarch64.tar: Dockerfile target/aarch64-unknown-linux-musl/release/ docker-images/x86_64.tar: Dockerfile target/x86_64-unknown-linux-musl/release/compat docker-images docker buildx build --build-arg ARCH=x86_64 --tag start9/x_system/compat --platform=linux/amd64 -o type=docker,dest=docker-images/x86_64.tar . -target/aarch64-unknown-linux-musl/release/compat: $(COMPAT_SRC) ../../backend/Cargo.lock +target/aarch64-unknown-linux-musl/release/compat: $(COMPAT_SRC) ../../core/Cargo.lock ARCH=aarch64 ./build.sh -target/x86_64-unknown-linux-musl/release/compat: $(COMPAT_SRC) ../../backend/Cargo.lock +target/x86_64-unknown-linux-musl/release/compat: $(COMPAT_SRC) ../../core/Cargo.lock ARCH=x86_64 ./build.sh diff --git a/frontend/.browserslistrc b/web/.browserslistrc similarity index 100% rename from frontend/.browserslistrc rename to web/.browserslistrc diff --git a/frontend/.editorconfig b/web/.editorconfig similarity index 100% rename from frontend/.editorconfig rename to web/.editorconfig diff --git a/frontend/.gitignore b/web/.gitignore similarity index 100% rename from frontend/.gitignore rename to web/.gitignore diff --git a/frontend/.prettierrc b/web/.prettierrc similarity index 100% rename from frontend/.prettierrc rename to web/.prettierrc diff --git a/frontend/README.md b/web/README.md similarity index 100% rename from frontend/README.md rename to web/README.md diff --git a/frontend/angular.json b/web/angular.json similarity index 100% rename from frontend/angular.json rename to web/angular.json diff --git a/frontend/build-config.js b/web/build-config.js similarity index 100% rename from frontend/build-config.js rename to web/build-config.js diff --git a/frontend/config-sample.json b/web/config-sample.json similarity index 100% rename from frontend/config-sample.json rename to web/config-sample.json diff --git a/frontend/ionic.config.json b/web/ionic.config.json similarity index 100% rename from frontend/ionic.config.json rename to web/ionic.config.json diff --git a/frontend/lint-staged.config.js b/web/lint-staged.config.js similarity index 100% rename from frontend/lint-staged.config.js rename to web/lint-staged.config.js diff --git a/frontend/package-lock.json b/web/package-lock.json similarity index 100% rename from frontend/package-lock.json rename to web/package-lock.json diff --git a/frontend/package.json b/web/package.json similarity index 100% rename from frontend/package.json rename to web/package.json diff --git a/frontend/patchdb-ui-seed.json b/web/patchdb-ui-seed.json similarity index 100% rename from frontend/patchdb-ui-seed.json rename to web/patchdb-ui-seed.json diff --git a/frontend/projects/diagnostic-ui/src/app/app-routing.module.ts b/web/projects/diagnostic-ui/src/app/app-routing.module.ts similarity index 59% rename from frontend/projects/diagnostic-ui/src/app/app-routing.module.ts rename to web/projects/diagnostic-ui/src/app/app-routing.module.ts index fffdfeece..f9f009b48 100644 --- a/frontend/projects/diagnostic-ui/src/app/app-routing.module.ts +++ b/web/projects/diagnostic-ui/src/app/app-routing.module.ts @@ -4,11 +4,13 @@ import { PreloadAllModules, RouterModule, Routes } from '@angular/router' const routes: Routes = [ { path: '', - loadChildren: () => import('./pages/home/home.module').then( m => m.HomePageModule) + loadChildren: () => + import('./pages/home/home.module').then(m => m.HomePageModule), }, { path: 'logs', - loadChildren: () => import('./pages/logs/logs.module').then( m => m.LogsPageModule) + loadChildren: () => + import('./pages/logs/logs.module').then(m => m.LogsPageModule), }, ] @@ -18,8 +20,8 @@ const routes: Routes = [ scrollPositionRestoration: 'enabled', preloadingStrategy: PreloadAllModules, useHash: true, - }) + }), ], - exports: [RouterModule] + exports: [RouterModule], }) -export class AppRoutingModule { } +export class AppRoutingModule {} diff --git a/frontend/projects/diagnostic-ui/src/app/app.component.html b/web/projects/diagnostic-ui/src/app/app.component.html similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/app.component.html rename to web/projects/diagnostic-ui/src/app/app.component.html diff --git a/frontend/projects/diagnostic-ui/src/app/app.component.scss b/web/projects/diagnostic-ui/src/app/app.component.scss similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/app.component.scss rename to web/projects/diagnostic-ui/src/app/app.component.scss diff --git a/frontend/projects/diagnostic-ui/src/app/app.component.ts b/web/projects/diagnostic-ui/src/app/app.component.ts similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/app.component.ts rename to web/projects/diagnostic-ui/src/app/app.component.ts diff --git a/frontend/projects/diagnostic-ui/src/app/app.module.ts b/web/projects/diagnostic-ui/src/app/app.module.ts similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/app.module.ts rename to web/projects/diagnostic-ui/src/app/app.module.ts diff --git a/frontend/projects/diagnostic-ui/src/app/pages/home/home-routing.module.ts b/web/projects/diagnostic-ui/src/app/pages/home/home-routing.module.ts similarity index 89% rename from frontend/projects/diagnostic-ui/src/app/pages/home/home-routing.module.ts rename to web/projects/diagnostic-ui/src/app/pages/home/home-routing.module.ts index 6ac28af67..efb1977dc 100644 --- a/frontend/projects/diagnostic-ui/src/app/pages/home/home-routing.module.ts +++ b/web/projects/diagnostic-ui/src/app/pages/home/home-routing.module.ts @@ -6,11 +6,11 @@ const routes: Routes = [ { path: '', component: HomePage, - } -]; + }, +] @NgModule({ imports: [RouterModule.forChild(routes)], - exports: [RouterModule] + exports: [RouterModule], }) export class HomePageRoutingModule {} diff --git a/frontend/projects/diagnostic-ui/src/app/pages/home/home.module.ts b/web/projects/diagnostic-ui/src/app/pages/home/home.module.ts similarity index 72% rename from frontend/projects/diagnostic-ui/src/app/pages/home/home.module.ts rename to web/projects/diagnostic-ui/src/app/pages/home/home.module.ts index 63184b7a2..1664b7c72 100644 --- a/frontend/projects/diagnostic-ui/src/app/pages/home/home.module.ts +++ b/web/projects/diagnostic-ui/src/app/pages/home/home.module.ts @@ -5,14 +5,8 @@ import { FormsModule } from '@angular/forms' import { HomePage } from './home.page' import { HomePageRoutingModule } from './home-routing.module' - @NgModule({ - imports: [ - CommonModule, - FormsModule, - IonicModule, - HomePageRoutingModule - ], - declarations: [HomePage] + imports: [CommonModule, FormsModule, IonicModule, HomePageRoutingModule], + declarations: [HomePage], }) export class HomePageModule {} diff --git a/frontend/projects/diagnostic-ui/src/app/pages/home/home.page.html b/web/projects/diagnostic-ui/src/app/pages/home/home.page.html similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/pages/home/home.page.html rename to web/projects/diagnostic-ui/src/app/pages/home/home.page.html diff --git a/frontend/projects/diagnostic-ui/src/app/pages/home/home.page.scss b/web/projects/diagnostic-ui/src/app/pages/home/home.page.scss similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/pages/home/home.page.scss rename to web/projects/diagnostic-ui/src/app/pages/home/home.page.scss diff --git a/frontend/projects/diagnostic-ui/src/app/pages/home/home.page.ts b/web/projects/diagnostic-ui/src/app/pages/home/home.page.ts similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/pages/home/home.page.ts rename to web/projects/diagnostic-ui/src/app/pages/home/home.page.ts diff --git a/frontend/projects/diagnostic-ui/src/app/pages/logs/logs.module.ts b/web/projects/diagnostic-ui/src/app/pages/logs/logs.module.ts similarity index 74% rename from frontend/projects/diagnostic-ui/src/app/pages/logs/logs.module.ts rename to web/projects/diagnostic-ui/src/app/pages/logs/logs.module.ts index da4d046b4..4ac28cefe 100644 --- a/frontend/projects/diagnostic-ui/src/app/pages/logs/logs.module.ts +++ b/web/projects/diagnostic-ui/src/app/pages/logs/logs.module.ts @@ -12,11 +12,7 @@ const routes: Routes = [ ] @NgModule({ - imports: [ - CommonModule, - IonicModule, - RouterModule.forChild(routes), - ], + imports: [CommonModule, IonicModule, RouterModule.forChild(routes)], declarations: [LogsPage], }) -export class LogsPageModule { } +export class LogsPageModule {} diff --git a/frontend/projects/diagnostic-ui/src/app/pages/logs/logs.page.html b/web/projects/diagnostic-ui/src/app/pages/logs/logs.page.html similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/pages/logs/logs.page.html rename to web/projects/diagnostic-ui/src/app/pages/logs/logs.page.html diff --git a/frontend/projects/diagnostic-ui/src/app/pages/logs/logs.page.scss b/web/projects/diagnostic-ui/src/app/pages/logs/logs.page.scss similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/pages/logs/logs.page.scss rename to web/projects/diagnostic-ui/src/app/pages/logs/logs.page.scss diff --git a/frontend/projects/diagnostic-ui/src/app/pages/logs/logs.page.ts b/web/projects/diagnostic-ui/src/app/pages/logs/logs.page.ts similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/pages/logs/logs.page.ts rename to web/projects/diagnostic-ui/src/app/pages/logs/logs.page.ts diff --git a/frontend/projects/diagnostic-ui/src/app/services/api/api.service.ts b/web/projects/diagnostic-ui/src/app/services/api/api.service.ts similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/services/api/api.service.ts rename to web/projects/diagnostic-ui/src/app/services/api/api.service.ts diff --git a/frontend/projects/diagnostic-ui/src/app/services/api/live-api.service.ts b/web/projects/diagnostic-ui/src/app/services/api/live-api.service.ts similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/services/api/live-api.service.ts rename to web/projects/diagnostic-ui/src/app/services/api/live-api.service.ts diff --git a/frontend/projects/diagnostic-ui/src/app/services/api/mock-api.service.ts b/web/projects/diagnostic-ui/src/app/services/api/mock-api.service.ts similarity index 100% rename from frontend/projects/diagnostic-ui/src/app/services/api/mock-api.service.ts rename to web/projects/diagnostic-ui/src/app/services/api/mock-api.service.ts diff --git a/frontend/projects/install-wizard/src/environments/environment.prod.ts b/web/projects/diagnostic-ui/src/environments/environment.prod.ts similarity index 100% rename from frontend/projects/install-wizard/src/environments/environment.prod.ts rename to web/projects/diagnostic-ui/src/environments/environment.prod.ts diff --git a/frontend/projects/install-wizard/src/environments/environment.ts b/web/projects/diagnostic-ui/src/environments/environment.ts similarity index 100% rename from frontend/projects/install-wizard/src/environments/environment.ts rename to web/projects/diagnostic-ui/src/environments/environment.ts diff --git a/frontend/projects/diagnostic-ui/src/index.html b/web/projects/diagnostic-ui/src/index.html similarity index 100% rename from frontend/projects/diagnostic-ui/src/index.html rename to web/projects/diagnostic-ui/src/index.html diff --git a/frontend/projects/diagnostic-ui/src/main.ts b/web/projects/diagnostic-ui/src/main.ts similarity index 100% rename from frontend/projects/diagnostic-ui/src/main.ts rename to web/projects/diagnostic-ui/src/main.ts diff --git a/frontend/projects/install-wizard/src/polyfills.ts b/web/projects/diagnostic-ui/src/polyfills.ts similarity index 100% rename from frontend/projects/install-wizard/src/polyfills.ts rename to web/projects/diagnostic-ui/src/polyfills.ts diff --git a/frontend/projects/diagnostic-ui/src/styles.scss b/web/projects/diagnostic-ui/src/styles.scss similarity index 100% rename from frontend/projects/diagnostic-ui/src/styles.scss rename to web/projects/diagnostic-ui/src/styles.scss diff --git a/frontend/projects/diagnostic-ui/src/zone-flags.ts b/web/projects/diagnostic-ui/src/zone-flags.ts similarity index 100% rename from frontend/projects/diagnostic-ui/src/zone-flags.ts rename to web/projects/diagnostic-ui/src/zone-flags.ts diff --git a/frontend/projects/diagnostic-ui/tsconfig.json b/web/projects/diagnostic-ui/tsconfig.json similarity index 100% rename from frontend/projects/diagnostic-ui/tsconfig.json rename to web/projects/diagnostic-ui/tsconfig.json diff --git a/frontend/projects/install-wizard/src/app/app-routing.module.ts b/web/projects/install-wizard/src/app/app-routing.module.ts similarity index 100% rename from frontend/projects/install-wizard/src/app/app-routing.module.ts rename to web/projects/install-wizard/src/app/app-routing.module.ts diff --git a/frontend/projects/install-wizard/src/app/app.component.html b/web/projects/install-wizard/src/app/app.component.html similarity index 100% rename from frontend/projects/install-wizard/src/app/app.component.html rename to web/projects/install-wizard/src/app/app.component.html diff --git a/frontend/projects/install-wizard/src/app/app.component.scss b/web/projects/install-wizard/src/app/app.component.scss similarity index 100% rename from frontend/projects/install-wizard/src/app/app.component.scss rename to web/projects/install-wizard/src/app/app.component.scss diff --git a/frontend/projects/install-wizard/src/app/app.component.ts b/web/projects/install-wizard/src/app/app.component.ts similarity index 100% rename from frontend/projects/install-wizard/src/app/app.component.ts rename to web/projects/install-wizard/src/app/app.component.ts diff --git a/frontend/projects/install-wizard/src/app/app.module.ts b/web/projects/install-wizard/src/app/app.module.ts similarity index 100% rename from frontend/projects/install-wizard/src/app/app.module.ts rename to web/projects/install-wizard/src/app/app.module.ts diff --git a/frontend/projects/install-wizard/src/app/pages/home/home.module.ts b/web/projects/install-wizard/src/app/pages/home/home.module.ts similarity index 100% rename from frontend/projects/install-wizard/src/app/pages/home/home.module.ts rename to web/projects/install-wizard/src/app/pages/home/home.module.ts diff --git a/frontend/projects/install-wizard/src/app/pages/home/home.page.html b/web/projects/install-wizard/src/app/pages/home/home.page.html similarity index 100% rename from frontend/projects/install-wizard/src/app/pages/home/home.page.html rename to web/projects/install-wizard/src/app/pages/home/home.page.html diff --git a/frontend/projects/install-wizard/src/app/pages/home/home.page.scss b/web/projects/install-wizard/src/app/pages/home/home.page.scss similarity index 100% rename from frontend/projects/install-wizard/src/app/pages/home/home.page.scss rename to web/projects/install-wizard/src/app/pages/home/home.page.scss diff --git a/frontend/projects/install-wizard/src/app/pages/home/home.page.ts b/web/projects/install-wizard/src/app/pages/home/home.page.ts similarity index 100% rename from frontend/projects/install-wizard/src/app/pages/home/home.page.ts rename to web/projects/install-wizard/src/app/pages/home/home.page.ts diff --git a/frontend/projects/install-wizard/src/app/services/api/api.service.ts b/web/projects/install-wizard/src/app/services/api/api.service.ts similarity index 100% rename from frontend/projects/install-wizard/src/app/services/api/api.service.ts rename to web/projects/install-wizard/src/app/services/api/api.service.ts diff --git a/frontend/projects/install-wizard/src/app/services/api/live-api.service.ts b/web/projects/install-wizard/src/app/services/api/live-api.service.ts similarity index 100% rename from frontend/projects/install-wizard/src/app/services/api/live-api.service.ts rename to web/projects/install-wizard/src/app/services/api/live-api.service.ts diff --git a/frontend/projects/install-wizard/src/app/services/api/mock-api.service.ts b/web/projects/install-wizard/src/app/services/api/mock-api.service.ts similarity index 100% rename from frontend/projects/install-wizard/src/app/services/api/mock-api.service.ts rename to web/projects/install-wizard/src/app/services/api/mock-api.service.ts diff --git a/frontend/projects/setup-wizard/src/environments/environment.prod.ts b/web/projects/install-wizard/src/environments/environment.prod.ts similarity index 100% rename from frontend/projects/setup-wizard/src/environments/environment.prod.ts rename to web/projects/install-wizard/src/environments/environment.prod.ts diff --git a/frontend/projects/setup-wizard/src/environments/environment.ts b/web/projects/install-wizard/src/environments/environment.ts similarity index 100% rename from frontend/projects/setup-wizard/src/environments/environment.ts rename to web/projects/install-wizard/src/environments/environment.ts diff --git a/frontend/projects/install-wizard/src/index.html b/web/projects/install-wizard/src/index.html similarity index 100% rename from frontend/projects/install-wizard/src/index.html rename to web/projects/install-wizard/src/index.html diff --git a/frontend/projects/install-wizard/src/main.ts b/web/projects/install-wizard/src/main.ts similarity index 100% rename from frontend/projects/install-wizard/src/main.ts rename to web/projects/install-wizard/src/main.ts diff --git a/frontend/projects/diagnostic-ui/src/polyfills.ts b/web/projects/install-wizard/src/polyfills.ts similarity index 99% rename from frontend/projects/diagnostic-ui/src/polyfills.ts rename to web/projects/install-wizard/src/polyfills.ts index f9f1dd06f..4437ced44 100644 --- a/frontend/projects/diagnostic-ui/src/polyfills.ts +++ b/web/projects/install-wizard/src/polyfills.ts @@ -59,7 +59,6 @@ import './zone-flags' */ import 'zone.js/dist/zone' // Included with Angular CLI. - /*************************************************************************************************** * APPLICATION IMPORTS */ diff --git a/frontend/projects/install-wizard/src/styles.scss b/web/projects/install-wizard/src/styles.scss similarity index 100% rename from frontend/projects/install-wizard/src/styles.scss rename to web/projects/install-wizard/src/styles.scss diff --git a/frontend/projects/install-wizard/src/zone-flags.ts b/web/projects/install-wizard/src/zone-flags.ts similarity index 100% rename from frontend/projects/install-wizard/src/zone-flags.ts rename to web/projects/install-wizard/src/zone-flags.ts diff --git a/frontend/projects/install-wizard/tsconfig.json b/web/projects/install-wizard/tsconfig.json similarity index 100% rename from frontend/projects/install-wizard/tsconfig.json rename to web/projects/install-wizard/tsconfig.json diff --git a/frontend/projects/marketplace/ng-package.json b/web/projects/marketplace/ng-package.json similarity index 100% rename from frontend/projects/marketplace/ng-package.json rename to web/projects/marketplace/ng-package.json diff --git a/frontend/projects/marketplace/package.json b/web/projects/marketplace/package.json similarity index 100% rename from frontend/projects/marketplace/package.json rename to web/projects/marketplace/package.json diff --git a/frontend/projects/marketplace/src/pages/list/categories/categories.component.html b/web/projects/marketplace/src/pages/list/categories/categories.component.html similarity index 100% rename from frontend/projects/marketplace/src/pages/list/categories/categories.component.html rename to web/projects/marketplace/src/pages/list/categories/categories.component.html diff --git a/frontend/projects/marketplace/src/pages/list/categories/categories.component.scss b/web/projects/marketplace/src/pages/list/categories/categories.component.scss similarity index 100% rename from frontend/projects/marketplace/src/pages/list/categories/categories.component.scss rename to web/projects/marketplace/src/pages/list/categories/categories.component.scss diff --git a/frontend/projects/marketplace/src/pages/list/categories/categories.component.ts b/web/projects/marketplace/src/pages/list/categories/categories.component.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/list/categories/categories.component.ts rename to web/projects/marketplace/src/pages/list/categories/categories.component.ts diff --git a/frontend/projects/marketplace/src/pages/list/categories/categories.module.ts b/web/projects/marketplace/src/pages/list/categories/categories.module.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/list/categories/categories.module.ts rename to web/projects/marketplace/src/pages/list/categories/categories.module.ts diff --git a/frontend/projects/marketplace/src/pages/list/item/item.component.html b/web/projects/marketplace/src/pages/list/item/item.component.html similarity index 100% rename from frontend/projects/marketplace/src/pages/list/item/item.component.html rename to web/projects/marketplace/src/pages/list/item/item.component.html diff --git a/frontend/projects/marketplace/src/pages/list/item/item.component.ts b/web/projects/marketplace/src/pages/list/item/item.component.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/list/item/item.component.ts rename to web/projects/marketplace/src/pages/list/item/item.component.ts diff --git a/frontend/projects/marketplace/src/pages/list/item/item.module.ts b/web/projects/marketplace/src/pages/list/item/item.module.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/list/item/item.module.ts rename to web/projects/marketplace/src/pages/list/item/item.module.ts diff --git a/frontend/projects/marketplace/src/pages/list/search/search.component.html b/web/projects/marketplace/src/pages/list/search/search.component.html similarity index 100% rename from frontend/projects/marketplace/src/pages/list/search/search.component.html rename to web/projects/marketplace/src/pages/list/search/search.component.html diff --git a/frontend/projects/marketplace/src/pages/list/search/search.component.scss b/web/projects/marketplace/src/pages/list/search/search.component.scss similarity index 100% rename from frontend/projects/marketplace/src/pages/list/search/search.component.scss rename to web/projects/marketplace/src/pages/list/search/search.component.scss diff --git a/frontend/projects/marketplace/src/pages/list/search/search.component.ts b/web/projects/marketplace/src/pages/list/search/search.component.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/list/search/search.component.ts rename to web/projects/marketplace/src/pages/list/search/search.component.ts diff --git a/frontend/projects/marketplace/src/pages/list/search/search.module.ts b/web/projects/marketplace/src/pages/list/search/search.module.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/list/search/search.module.ts rename to web/projects/marketplace/src/pages/list/search/search.module.ts diff --git a/frontend/projects/marketplace/src/pages/list/skeleton/skeleton.component.html b/web/projects/marketplace/src/pages/list/skeleton/skeleton.component.html similarity index 100% rename from frontend/projects/marketplace/src/pages/list/skeleton/skeleton.component.html rename to web/projects/marketplace/src/pages/list/skeleton/skeleton.component.html diff --git a/frontend/projects/marketplace/src/pages/list/skeleton/skeleton.component.ts b/web/projects/marketplace/src/pages/list/skeleton/skeleton.component.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/list/skeleton/skeleton.component.ts rename to web/projects/marketplace/src/pages/list/skeleton/skeleton.component.ts diff --git a/frontend/projects/marketplace/src/pages/list/skeleton/skeleton.module.ts b/web/projects/marketplace/src/pages/list/skeleton/skeleton.module.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/list/skeleton/skeleton.module.ts rename to web/projects/marketplace/src/pages/list/skeleton/skeleton.module.ts diff --git a/frontend/projects/marketplace/src/pages/release-notes/release-notes.component.html b/web/projects/marketplace/src/pages/release-notes/release-notes.component.html similarity index 100% rename from frontend/projects/marketplace/src/pages/release-notes/release-notes.component.html rename to web/projects/marketplace/src/pages/release-notes/release-notes.component.html diff --git a/frontend/projects/marketplace/src/pages/release-notes/release-notes.component.scss b/web/projects/marketplace/src/pages/release-notes/release-notes.component.scss similarity index 100% rename from frontend/projects/marketplace/src/pages/release-notes/release-notes.component.scss rename to web/projects/marketplace/src/pages/release-notes/release-notes.component.scss diff --git a/frontend/projects/marketplace/src/pages/release-notes/release-notes.component.ts b/web/projects/marketplace/src/pages/release-notes/release-notes.component.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/release-notes/release-notes.component.ts rename to web/projects/marketplace/src/pages/release-notes/release-notes.component.ts diff --git a/frontend/projects/marketplace/src/pages/release-notes/release-notes.module.ts b/web/projects/marketplace/src/pages/release-notes/release-notes.module.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/release-notes/release-notes.module.ts rename to web/projects/marketplace/src/pages/release-notes/release-notes.module.ts diff --git a/frontend/projects/marketplace/src/pages/show/about/about.component.html b/web/projects/marketplace/src/pages/show/about/about.component.html similarity index 100% rename from frontend/projects/marketplace/src/pages/show/about/about.component.html rename to web/projects/marketplace/src/pages/show/about/about.component.html diff --git a/frontend/projects/marketplace/src/pages/show/about/about.component.scss b/web/projects/marketplace/src/pages/show/about/about.component.scss similarity index 100% rename from frontend/projects/marketplace/src/pages/show/about/about.component.scss rename to web/projects/marketplace/src/pages/show/about/about.component.scss diff --git a/frontend/projects/marketplace/src/pages/show/about/about.component.ts b/web/projects/marketplace/src/pages/show/about/about.component.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/show/about/about.component.ts rename to web/projects/marketplace/src/pages/show/about/about.component.ts diff --git a/frontend/projects/marketplace/src/pages/show/about/about.module.ts b/web/projects/marketplace/src/pages/show/about/about.module.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/show/about/about.module.ts rename to web/projects/marketplace/src/pages/show/about/about.module.ts diff --git a/frontend/projects/marketplace/src/pages/show/additional/additional.component.html b/web/projects/marketplace/src/pages/show/additional/additional.component.html similarity index 100% rename from frontend/projects/marketplace/src/pages/show/additional/additional.component.html rename to web/projects/marketplace/src/pages/show/additional/additional.component.html diff --git a/frontend/projects/marketplace/src/pages/show/additional/additional.component.ts b/web/projects/marketplace/src/pages/show/additional/additional.component.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/show/additional/additional.component.ts rename to web/projects/marketplace/src/pages/show/additional/additional.component.ts diff --git a/frontend/projects/marketplace/src/pages/show/additional/additional.module.ts b/web/projects/marketplace/src/pages/show/additional/additional.module.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/show/additional/additional.module.ts rename to web/projects/marketplace/src/pages/show/additional/additional.module.ts diff --git a/frontend/projects/marketplace/src/pages/show/dependencies/dependencies.component.html b/web/projects/marketplace/src/pages/show/dependencies/dependencies.component.html similarity index 100% rename from frontend/projects/marketplace/src/pages/show/dependencies/dependencies.component.html rename to web/projects/marketplace/src/pages/show/dependencies/dependencies.component.html diff --git a/frontend/projects/marketplace/src/pages/show/dependencies/dependencies.component.ts b/web/projects/marketplace/src/pages/show/dependencies/dependencies.component.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/show/dependencies/dependencies.component.ts rename to web/projects/marketplace/src/pages/show/dependencies/dependencies.component.ts diff --git a/frontend/projects/marketplace/src/pages/show/dependencies/dependencies.module.ts b/web/projects/marketplace/src/pages/show/dependencies/dependencies.module.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/show/dependencies/dependencies.module.ts rename to web/projects/marketplace/src/pages/show/dependencies/dependencies.module.ts diff --git a/frontend/projects/marketplace/src/pages/show/package/package.component.html b/web/projects/marketplace/src/pages/show/package/package.component.html similarity index 100% rename from frontend/projects/marketplace/src/pages/show/package/package.component.html rename to web/projects/marketplace/src/pages/show/package/package.component.html diff --git a/frontend/projects/marketplace/src/pages/show/package/package.component.scss b/web/projects/marketplace/src/pages/show/package/package.component.scss similarity index 100% rename from frontend/projects/marketplace/src/pages/show/package/package.component.scss rename to web/projects/marketplace/src/pages/show/package/package.component.scss diff --git a/frontend/projects/marketplace/src/pages/show/package/package.component.ts b/web/projects/marketplace/src/pages/show/package/package.component.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/show/package/package.component.ts rename to web/projects/marketplace/src/pages/show/package/package.component.ts diff --git a/frontend/projects/marketplace/src/pages/show/package/package.module.ts b/web/projects/marketplace/src/pages/show/package/package.module.ts similarity index 100% rename from frontend/projects/marketplace/src/pages/show/package/package.module.ts rename to web/projects/marketplace/src/pages/show/package/package.module.ts diff --git a/frontend/projects/marketplace/src/pipes/filter-packages.pipe.ts b/web/projects/marketplace/src/pipes/filter-packages.pipe.ts similarity index 100% rename from frontend/projects/marketplace/src/pipes/filter-packages.pipe.ts rename to web/projects/marketplace/src/pipes/filter-packages.pipe.ts diff --git a/frontend/projects/marketplace/src/pipes/mime-type.pipe.ts b/web/projects/marketplace/src/pipes/mime-type.pipe.ts similarity index 100% rename from frontend/projects/marketplace/src/pipes/mime-type.pipe.ts rename to web/projects/marketplace/src/pipes/mime-type.pipe.ts diff --git a/frontend/projects/marketplace/src/public-api.ts b/web/projects/marketplace/src/public-api.ts similarity index 100% rename from frontend/projects/marketplace/src/public-api.ts rename to web/projects/marketplace/src/public-api.ts diff --git a/frontend/projects/marketplace/src/services/marketplace.service.ts b/web/projects/marketplace/src/services/marketplace.service.ts similarity index 100% rename from frontend/projects/marketplace/src/services/marketplace.service.ts rename to web/projects/marketplace/src/services/marketplace.service.ts diff --git a/frontend/projects/marketplace/src/types.ts b/web/projects/marketplace/src/types.ts similarity index 100% rename from frontend/projects/marketplace/src/types.ts rename to web/projects/marketplace/src/types.ts diff --git a/frontend/projects/marketplace/tsconfig.json b/web/projects/marketplace/tsconfig.json similarity index 100% rename from frontend/projects/marketplace/tsconfig.json rename to web/projects/marketplace/tsconfig.json diff --git a/frontend/projects/setup-wizard/src/app/app-routing.module.ts b/web/projects/setup-wizard/src/app/app-routing.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/app-routing.module.ts rename to web/projects/setup-wizard/src/app/app-routing.module.ts diff --git a/frontend/projects/setup-wizard/src/app/app.component.html b/web/projects/setup-wizard/src/app/app.component.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/app.component.html rename to web/projects/setup-wizard/src/app/app.component.html diff --git a/frontend/projects/setup-wizard/src/app/app.component.scss b/web/projects/setup-wizard/src/app/app.component.scss similarity index 100% rename from frontend/projects/setup-wizard/src/app/app.component.scss rename to web/projects/setup-wizard/src/app/app.component.scss diff --git a/frontend/projects/setup-wizard/src/app/app.component.ts b/web/projects/setup-wizard/src/app/app.component.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/app.component.ts rename to web/projects/setup-wizard/src/app/app.component.ts diff --git a/frontend/projects/setup-wizard/src/app/app.module.ts b/web/projects/setup-wizard/src/app/app.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/app.module.ts rename to web/projects/setup-wizard/src/app/app.module.ts diff --git a/frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.module.ts b/web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.module.ts similarity index 57% rename from frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.module.ts rename to web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.module.ts index f10455e0c..b5c07d37c 100644 --- a/frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.module.ts +++ b/web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.module.ts @@ -5,16 +5,8 @@ import { FormsModule } from '@angular/forms' import { CifsModal } from './cifs-modal.page' @NgModule({ - declarations: [ - CifsModal, - ], - imports: [ - CommonModule, - FormsModule, - IonicModule, - ], - exports: [ - CifsModal, - ], + declarations: [CifsModal], + imports: [CommonModule, FormsModule, IonicModule], + exports: [CifsModal], }) -export class CifsModalModule { } +export class CifsModalModule {} diff --git a/frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.html b/web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.html similarity index 91% rename from frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.html rename to web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.html index ebec1b21f..88164a510 100644 --- a/frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.html +++ b/web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.html @@ -1,6 +1,6 @@ - Connect Network Folder + Connect Network Folder @@ -19,10 +19,9 @@ >

- Hostname is required. e.g. 'My Computer' OR - 'my-computer.local' + + Hostname is required. e.g. 'My Computer' OR 'my-computer.local' +

Path *

diff --git a/frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.scss b/web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.scss similarity index 100% rename from frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.scss rename to web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.scss diff --git a/frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.ts b/web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.ts rename to web/projects/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.ts diff --git a/frontend/projects/setup-wizard/src/app/modals/password/password.module.ts b/web/projects/setup-wizard/src/app/modals/password/password.module.ts similarity index 56% rename from frontend/projects/setup-wizard/src/app/modals/password/password.module.ts rename to web/projects/setup-wizard/src/app/modals/password/password.module.ts index 416c558f5..f5c9e9223 100644 --- a/frontend/projects/setup-wizard/src/app/modals/password/password.module.ts +++ b/web/projects/setup-wizard/src/app/modals/password/password.module.ts @@ -5,16 +5,8 @@ import { FormsModule } from '@angular/forms' import { PasswordPage } from './password.page' @NgModule({ - declarations: [ - PasswordPage, - ], - imports: [ - CommonModule, - FormsModule, - IonicModule, - ], - exports: [ - PasswordPage, - ], + declarations: [PasswordPage], + imports: [CommonModule, FormsModule, IonicModule], + exports: [PasswordPage], }) -export class PasswordPageModule { } +export class PasswordPageModule {} diff --git a/frontend/projects/setup-wizard/src/app/modals/password/password.page.html b/web/projects/setup-wizard/src/app/modals/password/password.page.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/modals/password/password.page.html rename to web/projects/setup-wizard/src/app/modals/password/password.page.html diff --git a/frontend/projects/setup-wizard/src/app/modals/password/password.page.scss b/web/projects/setup-wizard/src/app/modals/password/password.page.scss similarity index 100% rename from frontend/projects/setup-wizard/src/app/modals/password/password.page.scss rename to web/projects/setup-wizard/src/app/modals/password/password.page.scss diff --git a/frontend/projects/setup-wizard/src/app/modals/password/password.page.ts b/web/projects/setup-wizard/src/app/modals/password/password.page.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/modals/password/password.page.ts rename to web/projects/setup-wizard/src/app/modals/password/password.page.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach-routing.module.ts b/web/projects/setup-wizard/src/app/pages/attach/attach-routing.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/attach/attach-routing.module.ts rename to web/projects/setup-wizard/src/app/pages/attach/attach-routing.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach.module.ts b/web/projects/setup-wizard/src/app/pages/attach/attach.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/attach/attach.module.ts rename to web/projects/setup-wizard/src/app/pages/attach/attach.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.html b/web/projects/setup-wizard/src/app/pages/attach/attach.page.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/attach/attach.page.html rename to web/projects/setup-wizard/src/app/pages/attach/attach.page.html diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.scss b/web/projects/setup-wizard/src/app/pages/attach/attach.page.scss similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/attach/attach.page.scss rename to web/projects/setup-wizard/src/app/pages/attach/attach.page.scss diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.ts b/web/projects/setup-wizard/src/app/pages/attach/attach.page.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/attach/attach.page.ts rename to web/projects/setup-wizard/src/app/pages/attach/attach.page.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy-routing.module.ts b/web/projects/setup-wizard/src/app/pages/embassy/embassy-routing.module.ts similarity index 87% rename from frontend/projects/setup-wizard/src/app/pages/embassy/embassy-routing.module.ts rename to web/projects/setup-wizard/src/app/pages/embassy/embassy-routing.module.ts index 9265ba721..acd82b7ac 100644 --- a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy-routing.module.ts +++ b/web/projects/setup-wizard/src/app/pages/embassy/embassy-routing.module.ts @@ -13,4 +13,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class EmbassyPageRoutingModule { } +export class EmbassyPageRoutingModule {} diff --git a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.module.ts b/web/projects/setup-wizard/src/app/pages/embassy/embassy.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/embassy/embassy.module.ts rename to web/projects/setup-wizard/src/app/pages/embassy/embassy.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.html b/web/projects/setup-wizard/src/app/pages/embassy/embassy.page.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.html rename to web/projects/setup-wizard/src/app/pages/embassy/embassy.page.html diff --git a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.scss b/web/projects/setup-wizard/src/app/pages/embassy/embassy.page.scss similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.scss rename to web/projects/setup-wizard/src/app/pages/embassy/embassy.page.scss diff --git a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts b/web/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts rename to web/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/home/home-routing.module.ts b/web/projects/setup-wizard/src/app/pages/home/home-routing.module.ts similarity index 88% rename from frontend/projects/setup-wizard/src/app/pages/home/home-routing.module.ts rename to web/projects/setup-wizard/src/app/pages/home/home-routing.module.ts index fcc236c16..efb1977dc 100644 --- a/frontend/projects/setup-wizard/src/app/pages/home/home-routing.module.ts +++ b/web/projects/setup-wizard/src/app/pages/home/home-routing.module.ts @@ -13,4 +13,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class HomePageRoutingModule { } +export class HomePageRoutingModule {} diff --git a/frontend/projects/setup-wizard/src/app/pages/home/home.module.ts b/web/projects/setup-wizard/src/app/pages/home/home.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/home/home.module.ts rename to web/projects/setup-wizard/src/app/pages/home/home.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/home/home.page.html b/web/projects/setup-wizard/src/app/pages/home/home.page.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/home/home.page.html rename to web/projects/setup-wizard/src/app/pages/home/home.page.html diff --git a/frontend/projects/setup-wizard/src/app/pages/home/home.page.scss b/web/projects/setup-wizard/src/app/pages/home/home.page.scss similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/home/home.page.scss rename to web/projects/setup-wizard/src/app/pages/home/home.page.scss diff --git a/frontend/projects/setup-wizard/src/app/pages/home/home.page.ts b/web/projects/setup-wizard/src/app/pages/home/home.page.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/home/home.page.ts rename to web/projects/setup-wizard/src/app/pages/home/home.page.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/loading/loading.module.ts b/web/projects/setup-wizard/src/app/pages/loading/loading.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/loading/loading.module.ts rename to web/projects/setup-wizard/src/app/pages/loading/loading.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/loading/loading.page.html b/web/projects/setup-wizard/src/app/pages/loading/loading.page.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/loading/loading.page.html rename to web/projects/setup-wizard/src/app/pages/loading/loading.page.html diff --git a/web/projects/setup-wizard/src/app/pages/loading/loading.page.scss b/web/projects/setup-wizard/src/app/pages/loading/loading.page.scss new file mode 100644 index 000000000..87bfffa33 --- /dev/null +++ b/web/projects/setup-wizard/src/app/pages/loading/loading.page.scss @@ -0,0 +1,3 @@ +ion-card-title { + font-size: 42px; +} \ No newline at end of file diff --git a/frontend/projects/setup-wizard/src/app/pages/loading/loading.page.ts b/web/projects/setup-wizard/src/app/pages/loading/loading.page.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/loading/loading.page.ts rename to web/projects/setup-wizard/src/app/pages/loading/loading.page.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/recover/drive-status.component.html b/web/projects/setup-wizard/src/app/pages/recover/drive-status.component.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/recover/drive-status.component.html rename to web/projects/setup-wizard/src/app/pages/recover/drive-status.component.html diff --git a/frontend/projects/setup-wizard/src/app/pages/recover/recover-routing.module.ts b/web/projects/setup-wizard/src/app/pages/recover/recover-routing.module.ts similarity index 87% rename from frontend/projects/setup-wizard/src/app/pages/recover/recover-routing.module.ts rename to web/projects/setup-wizard/src/app/pages/recover/recover-routing.module.ts index 524458fa8..d91bc0831 100644 --- a/frontend/projects/setup-wizard/src/app/pages/recover/recover-routing.module.ts +++ b/web/projects/setup-wizard/src/app/pages/recover/recover-routing.module.ts @@ -13,4 +13,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class RecoverPageRoutingModule { } +export class RecoverPageRoutingModule {} diff --git a/frontend/projects/setup-wizard/src/app/pages/recover/recover.module.ts b/web/projects/setup-wizard/src/app/pages/recover/recover.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/recover/recover.module.ts rename to web/projects/setup-wizard/src/app/pages/recover/recover.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/recover/recover.page.html b/web/projects/setup-wizard/src/app/pages/recover/recover.page.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/recover/recover.page.html rename to web/projects/setup-wizard/src/app/pages/recover/recover.page.html diff --git a/frontend/projects/setup-wizard/src/app/pages/recover/recover.page.scss b/web/projects/setup-wizard/src/app/pages/recover/recover.page.scss similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/recover/recover.page.scss rename to web/projects/setup-wizard/src/app/pages/recover/recover.page.scss diff --git a/frontend/projects/setup-wizard/src/app/pages/recover/recover.page.ts b/web/projects/setup-wizard/src/app/pages/recover/recover.page.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/recover/recover.page.ts rename to web/projects/setup-wizard/src/app/pages/recover/recover.page.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/success/download-doc/download-doc.component.html b/web/projects/setup-wizard/src/app/pages/success/download-doc/download-doc.component.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/success/download-doc/download-doc.component.html rename to web/projects/setup-wizard/src/app/pages/success/download-doc/download-doc.component.html diff --git a/frontend/projects/setup-wizard/src/app/pages/success/download-doc/download-doc.component.ts b/web/projects/setup-wizard/src/app/pages/success/download-doc/download-doc.component.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/success/download-doc/download-doc.component.ts rename to web/projects/setup-wizard/src/app/pages/success/download-doc/download-doc.component.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/success/success-routing.module.ts b/web/projects/setup-wizard/src/app/pages/success/success-routing.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/success/success-routing.module.ts rename to web/projects/setup-wizard/src/app/pages/success/success-routing.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/success/success.module.ts b/web/projects/setup-wizard/src/app/pages/success/success.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/success/success.module.ts rename to web/projects/setup-wizard/src/app/pages/success/success.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/success/success.page.html b/web/projects/setup-wizard/src/app/pages/success/success.page.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/success/success.page.html rename to web/projects/setup-wizard/src/app/pages/success/success.page.html diff --git a/frontend/projects/setup-wizard/src/app/pages/success/success.page.scss b/web/projects/setup-wizard/src/app/pages/success/success.page.scss similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/success/success.page.scss rename to web/projects/setup-wizard/src/app/pages/success/success.page.scss diff --git a/frontend/projects/setup-wizard/src/app/pages/success/success.page.ts b/web/projects/setup-wizard/src/app/pages/success/success.page.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/success/success.page.ts rename to web/projects/setup-wizard/src/app/pages/success/success.page.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/transfer/transfer-routing.module.ts b/web/projects/setup-wizard/src/app/pages/transfer/transfer-routing.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/transfer/transfer-routing.module.ts rename to web/projects/setup-wizard/src/app/pages/transfer/transfer-routing.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.module.ts b/web/projects/setup-wizard/src/app/pages/transfer/transfer.module.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/transfer/transfer.module.ts rename to web/projects/setup-wizard/src/app/pages/transfer/transfer.module.ts diff --git a/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.html b/web/projects/setup-wizard/src/app/pages/transfer/transfer.page.html similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.html rename to web/projects/setup-wizard/src/app/pages/transfer/transfer.page.html diff --git a/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.scss b/web/projects/setup-wizard/src/app/pages/transfer/transfer.page.scss similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.scss rename to web/projects/setup-wizard/src/app/pages/transfer/transfer.page.scss diff --git a/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.ts b/web/projects/setup-wizard/src/app/pages/transfer/transfer.page.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.ts rename to web/projects/setup-wizard/src/app/pages/transfer/transfer.page.ts diff --git a/frontend/projects/setup-wizard/src/app/services/api/api.service.ts b/web/projects/setup-wizard/src/app/services/api/api.service.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/services/api/api.service.ts rename to web/projects/setup-wizard/src/app/services/api/api.service.ts diff --git a/frontend/projects/setup-wizard/src/app/services/api/live-api.service.ts b/web/projects/setup-wizard/src/app/services/api/live-api.service.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/services/api/live-api.service.ts rename to web/projects/setup-wizard/src/app/services/api/live-api.service.ts diff --git a/frontend/projects/setup-wizard/src/app/services/api/mock-api.service.ts b/web/projects/setup-wizard/src/app/services/api/mock-api.service.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/services/api/mock-api.service.ts rename to web/projects/setup-wizard/src/app/services/api/mock-api.service.ts diff --git a/frontend/projects/setup-wizard/src/app/services/state.service.ts b/web/projects/setup-wizard/src/app/services/state.service.ts similarity index 100% rename from frontend/projects/setup-wizard/src/app/services/state.service.ts rename to web/projects/setup-wizard/src/app/services/state.service.ts diff --git a/frontend/projects/diagnostic-ui/src/environments/environment.prod.ts b/web/projects/setup-wizard/src/environments/environment.prod.ts similarity index 60% rename from frontend/projects/diagnostic-ui/src/environments/environment.prod.ts rename to web/projects/setup-wizard/src/environments/environment.prod.ts index bc0327dbe..970e25bd7 100644 --- a/frontend/projects/diagnostic-ui/src/environments/environment.prod.ts +++ b/web/projects/setup-wizard/src/environments/environment.prod.ts @@ -1,3 +1,3 @@ export const environment = { - production: true + production: true, } diff --git a/frontend/projects/diagnostic-ui/src/environments/environment.ts b/web/projects/setup-wizard/src/environments/environment.ts similarity index 96% rename from frontend/projects/diagnostic-ui/src/environments/environment.ts rename to web/projects/setup-wizard/src/environments/environment.ts index 745ee023b..5c68c17ab 100644 --- a/frontend/projects/diagnostic-ui/src/environments/environment.ts +++ b/web/projects/setup-wizard/src/environments/environment.ts @@ -3,7 +3,7 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false, } /* diff --git a/frontend/projects/setup-wizard/src/index.html b/web/projects/setup-wizard/src/index.html similarity index 100% rename from frontend/projects/setup-wizard/src/index.html rename to web/projects/setup-wizard/src/index.html diff --git a/frontend/projects/setup-wizard/src/main.ts b/web/projects/setup-wizard/src/main.ts similarity index 100% rename from frontend/projects/setup-wizard/src/main.ts rename to web/projects/setup-wizard/src/main.ts diff --git a/frontend/projects/setup-wizard/src/polyfills.ts b/web/projects/setup-wizard/src/polyfills.ts similarity index 97% rename from frontend/projects/setup-wizard/src/polyfills.ts rename to web/projects/setup-wizard/src/polyfills.ts index 219f4a27d..4437ced44 100644 --- a/frontend/projects/setup-wizard/src/polyfills.ts +++ b/web/projects/setup-wizard/src/polyfills.ts @@ -57,8 +57,7 @@ import './zone-flags' /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone' // Included with Angular CLI. - +import 'zone.js/dist/zone' // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS diff --git a/frontend/projects/setup-wizard/src/styles.scss b/web/projects/setup-wizard/src/styles.scss similarity index 100% rename from frontend/projects/setup-wizard/src/styles.scss rename to web/projects/setup-wizard/src/styles.scss diff --git a/frontend/projects/setup-wizard/src/zone-flags.ts b/web/projects/setup-wizard/src/zone-flags.ts similarity index 100% rename from frontend/projects/setup-wizard/src/zone-flags.ts rename to web/projects/setup-wizard/src/zone-flags.ts diff --git a/frontend/projects/setup-wizard/tsconfig.json b/web/projects/setup-wizard/tsconfig.json similarity index 100% rename from frontend/projects/setup-wizard/tsconfig.json rename to web/projects/setup-wizard/tsconfig.json diff --git a/frontend/projects/shared/assets/fonts/Benton_Sans/BentonSans-Regular.otf b/web/projects/shared/assets/fonts/Benton_Sans/BentonSans-Regular.otf similarity index 100% rename from frontend/projects/shared/assets/fonts/Benton_Sans/BentonSans-Regular.otf rename to web/projects/shared/assets/fonts/Benton_Sans/BentonSans-Regular.otf diff --git a/frontend/projects/shared/assets/fonts/Courier_New/CourierNew-Bold.ttf b/web/projects/shared/assets/fonts/Courier_New/CourierNew-Bold.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Courier_New/CourierNew-Bold.ttf rename to web/projects/shared/assets/fonts/Courier_New/CourierNew-Bold.ttf diff --git a/frontend/projects/shared/assets/fonts/Courier_New/CourierNew-Regular.ttf b/web/projects/shared/assets/fonts/Courier_New/CourierNew-Regular.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Courier_New/CourierNew-Regular.ttf rename to web/projects/shared/assets/fonts/Courier_New/CourierNew-Regular.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Black.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-Black.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Black.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-Black.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-BlackItalic.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-BlackItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-BlackItalic.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-BlackItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Bold.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-Bold.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Bold.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-Bold.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-BoldItalic.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-BoldItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-BoldItalic.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-BoldItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraBold.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraBold.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraBold.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraBold.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraLight.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraLight.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraLight.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraLight.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Italic.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-Italic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Italic.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-Italic.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Light.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-Light.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Light.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-Light.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-LightItalic.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-LightItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-LightItalic.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-LightItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Medium.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-Medium.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Medium.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-Medium.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-MediumItalic.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-MediumItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-MediumItalic.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-MediumItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Regular.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-Regular.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Regular.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-Regular.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-SemiBold.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-SemiBold.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-SemiBold.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-SemiBold.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Thin.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-Thin.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-Thin.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-Thin.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ThinItalic.ttf b/web/projects/shared/assets/fonts/Montserrat/Montserrat-ThinItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/Montserrat-ThinItalic.ttf rename to web/projects/shared/assets/fonts/Montserrat/Montserrat-ThinItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Montserrat/OFL.txt b/web/projects/shared/assets/fonts/Montserrat/OFL.txt similarity index 100% rename from frontend/projects/shared/assets/fonts/Montserrat/OFL.txt rename to web/projects/shared/assets/fonts/Montserrat/OFL.txt diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/LICENSE.txt b/web/projects/shared/assets/fonts/Open_Sans/LICENSE.txt similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/LICENSE.txt rename to web/projects/shared/assets/fonts/Open_Sans/LICENSE.txt diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-Bold.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-Bold.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-Bold.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-Bold.ttf diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-BoldItalic.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-BoldItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-BoldItalic.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-BoldItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-ExtraBold.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-ExtraBold.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-ExtraBold.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-ExtraBold.ttf diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-ExtraBoldItalic.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-ExtraBoldItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-ExtraBoldItalic.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-ExtraBoldItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-Italic.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-Italic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-Italic.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-Italic.ttf diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-Light.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-Light.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-Light.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-Light.ttf diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-LightItalic.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-LightItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-LightItalic.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-LightItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-Regular.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-Regular.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-Regular.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-Regular.ttf diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-SemiBold.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-SemiBold.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-SemiBold.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-SemiBold.ttf diff --git a/frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-SemiBoldItalic.ttf b/web/projects/shared/assets/fonts/Open_Sans/OpenSans-SemiBoldItalic.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Open_Sans/OpenSans-SemiBoldItalic.ttf rename to web/projects/shared/assets/fonts/Open_Sans/OpenSans-SemiBoldItalic.ttf diff --git a/frontend/projects/shared/assets/fonts/Redacted/redacted.regular.ttf b/web/projects/shared/assets/fonts/Redacted/redacted.regular.ttf similarity index 100% rename from frontend/projects/shared/assets/fonts/Redacted/redacted.regular.ttf rename to web/projects/shared/assets/fonts/Redacted/redacted.regular.ttf diff --git a/frontend/projects/shared/assets/fonts/text-security-disc.woff2 b/web/projects/shared/assets/fonts/text-security-disc.woff2 similarity index 100% rename from frontend/projects/shared/assets/fonts/text-security-disc.woff2 rename to web/projects/shared/assets/fonts/text-security-disc.woff2 diff --git a/frontend/projects/shared/assets/icon/favicon.ico b/web/projects/shared/assets/icon/favicon.ico similarity index 100% rename from frontend/projects/shared/assets/icon/favicon.ico rename to web/projects/shared/assets/icon/favicon.ico diff --git a/frontend/projects/shared/assets/img/community-store.png b/web/projects/shared/assets/img/community-store.png similarity index 100% rename from frontend/projects/shared/assets/img/community-store.png rename to web/projects/shared/assets/img/community-store.png diff --git a/frontend/projects/shared/assets/img/icon.png b/web/projects/shared/assets/img/icon.png similarity index 100% rename from frontend/projects/shared/assets/img/icon.png rename to web/projects/shared/assets/img/icon.png diff --git a/frontend/projects/shared/assets/img/icon_apple_touch.png b/web/projects/shared/assets/img/icon_apple_touch.png similarity index 100% rename from frontend/projects/shared/assets/img/icon_apple_touch.png rename to web/projects/shared/assets/img/icon_apple_touch.png diff --git a/frontend/projects/shared/assets/img/icons/bitcoin.svg b/web/projects/shared/assets/img/icons/bitcoin.svg similarity index 100% rename from frontend/projects/shared/assets/img/icons/bitcoin.svg rename to web/projects/shared/assets/img/icons/bitcoin.svg diff --git a/frontend/projects/shared/assets/img/icons/snek.png b/web/projects/shared/assets/img/icons/snek.png similarity index 100% rename from frontend/projects/shared/assets/img/icons/snek.png rename to web/projects/shared/assets/img/icons/snek.png diff --git a/frontend/projects/shared/assets/img/icons/wifi-0.png b/web/projects/shared/assets/img/icons/wifi-0.png similarity index 100% rename from frontend/projects/shared/assets/img/icons/wifi-0.png rename to web/projects/shared/assets/img/icons/wifi-0.png diff --git a/frontend/projects/shared/assets/img/icons/wifi-1.png b/web/projects/shared/assets/img/icons/wifi-1.png similarity index 100% rename from frontend/projects/shared/assets/img/icons/wifi-1.png rename to web/projects/shared/assets/img/icons/wifi-1.png diff --git a/frontend/projects/shared/assets/img/icons/wifi-2.png b/web/projects/shared/assets/img/icons/wifi-2.png similarity index 100% rename from frontend/projects/shared/assets/img/icons/wifi-2.png rename to web/projects/shared/assets/img/icons/wifi-2.png diff --git a/frontend/projects/shared/assets/img/icons/wifi-3.png b/web/projects/shared/assets/img/icons/wifi-3.png similarity index 100% rename from frontend/projects/shared/assets/img/icons/wifi-3.png rename to web/projects/shared/assets/img/icons/wifi-3.png diff --git a/frontend/projects/shared/assets/img/service-icons/bitcoind.svg b/web/projects/shared/assets/img/service-icons/bitcoind.svg similarity index 100% rename from frontend/projects/shared/assets/img/service-icons/bitcoind.svg rename to web/projects/shared/assets/img/service-icons/bitcoind.svg diff --git a/frontend/projects/shared/assets/img/service-icons/btc-rpc-proxy.png b/web/projects/shared/assets/img/service-icons/btc-rpc-proxy.png similarity index 100% rename from frontend/projects/shared/assets/img/service-icons/btc-rpc-proxy.png rename to web/projects/shared/assets/img/service-icons/btc-rpc-proxy.png diff --git a/frontend/projects/shared/assets/img/service-icons/lnd.png b/web/projects/shared/assets/img/service-icons/lnd.png similarity index 100% rename from frontend/projects/shared/assets/img/service-icons/lnd.png rename to web/projects/shared/assets/img/service-icons/lnd.png diff --git a/frontend/projects/shared/assets/markdown/md-sample.md b/web/projects/shared/assets/markdown/md-sample.md similarity index 100% rename from frontend/projects/shared/assets/markdown/md-sample.md rename to web/projects/shared/assets/markdown/md-sample.md diff --git a/frontend/projects/shared/ng-package.json b/web/projects/shared/ng-package.json similarity index 100% rename from frontend/projects/shared/ng-package.json rename to web/projects/shared/ng-package.json diff --git a/frontend/projects/shared/package.json b/web/projects/shared/package.json similarity index 100% rename from frontend/projects/shared/package.json rename to web/projects/shared/package.json diff --git a/frontend/projects/shared/src/classes/http-error.ts b/web/projects/shared/src/classes/http-error.ts similarity index 100% rename from frontend/projects/shared/src/classes/http-error.ts rename to web/projects/shared/src/classes/http-error.ts diff --git a/frontend/projects/shared/src/classes/rpc-error.ts b/web/projects/shared/src/classes/rpc-error.ts similarity index 100% rename from frontend/projects/shared/src/classes/rpc-error.ts rename to web/projects/shared/src/classes/rpc-error.ts diff --git a/frontend/projects/shared/src/components/alert/alert-button.directive.ts b/web/projects/shared/src/components/alert/alert-button.directive.ts similarity index 100% rename from frontend/projects/shared/src/components/alert/alert-button.directive.ts rename to web/projects/shared/src/components/alert/alert-button.directive.ts diff --git a/frontend/projects/shared/src/components/alert/alert-input.directive.ts b/web/projects/shared/src/components/alert/alert-input.directive.ts similarity index 100% rename from frontend/projects/shared/src/components/alert/alert-input.directive.ts rename to web/projects/shared/src/components/alert/alert-input.directive.ts diff --git a/frontend/projects/shared/src/components/alert/alert.component.ts b/web/projects/shared/src/components/alert/alert.component.ts similarity index 100% rename from frontend/projects/shared/src/components/alert/alert.component.ts rename to web/projects/shared/src/components/alert/alert.component.ts diff --git a/frontend/projects/shared/src/components/alert/alert.module.ts b/web/projects/shared/src/components/alert/alert.module.ts similarity index 100% rename from frontend/projects/shared/src/components/alert/alert.module.ts rename to web/projects/shared/src/components/alert/alert.module.ts diff --git a/frontend/projects/shared/src/components/loading/loading.component.html b/web/projects/shared/src/components/loading/loading.component.html similarity index 100% rename from frontend/projects/shared/src/components/loading/loading.component.html rename to web/projects/shared/src/components/loading/loading.component.html diff --git a/frontend/projects/shared/src/components/loading/loading.component.scss b/web/projects/shared/src/components/loading/loading.component.scss similarity index 100% rename from frontend/projects/shared/src/components/loading/loading.component.scss rename to web/projects/shared/src/components/loading/loading.component.scss diff --git a/frontend/projects/shared/src/components/loading/loading.component.ts b/web/projects/shared/src/components/loading/loading.component.ts similarity index 100% rename from frontend/projects/shared/src/components/loading/loading.component.ts rename to web/projects/shared/src/components/loading/loading.component.ts diff --git a/frontend/projects/shared/src/components/loading/loading.module.ts b/web/projects/shared/src/components/loading/loading.module.ts similarity index 100% rename from frontend/projects/shared/src/components/loading/loading.module.ts rename to web/projects/shared/src/components/loading/loading.module.ts diff --git a/frontend/projects/shared/src/components/loading/logs-window/logs-window.component.html b/web/projects/shared/src/components/loading/logs-window/logs-window.component.html similarity index 100% rename from frontend/projects/shared/src/components/loading/logs-window/logs-window.component.html rename to web/projects/shared/src/components/loading/logs-window/logs-window.component.html diff --git a/frontend/projects/shared/src/components/loading/logs-window/logs-window.component.scss b/web/projects/shared/src/components/loading/logs-window/logs-window.component.scss similarity index 100% rename from frontend/projects/shared/src/components/loading/logs-window/logs-window.component.scss rename to web/projects/shared/src/components/loading/logs-window/logs-window.component.scss diff --git a/frontend/projects/shared/src/components/loading/logs-window/logs-window.component.ts b/web/projects/shared/src/components/loading/logs-window/logs-window.component.ts similarity index 100% rename from frontend/projects/shared/src/components/loading/logs-window/logs-window.component.ts rename to web/projects/shared/src/components/loading/logs-window/logs-window.component.ts diff --git a/frontend/projects/shared/src/components/markdown/markdown.component.html b/web/projects/shared/src/components/markdown/markdown.component.html similarity index 100% rename from frontend/projects/shared/src/components/markdown/markdown.component.html rename to web/projects/shared/src/components/markdown/markdown.component.html diff --git a/frontend/projects/shared/src/components/markdown/markdown.component.module.ts b/web/projects/shared/src/components/markdown/markdown.component.module.ts similarity index 100% rename from frontend/projects/shared/src/components/markdown/markdown.component.module.ts rename to web/projects/shared/src/components/markdown/markdown.component.module.ts diff --git a/frontend/projects/shared/src/components/markdown/markdown.component.scss b/web/projects/shared/src/components/markdown/markdown.component.scss similarity index 100% rename from frontend/projects/shared/src/components/markdown/markdown.component.scss rename to web/projects/shared/src/components/markdown/markdown.component.scss diff --git a/frontend/projects/shared/src/components/markdown/markdown.component.ts b/web/projects/shared/src/components/markdown/markdown.component.ts similarity index 100% rename from frontend/projects/shared/src/components/markdown/markdown.component.ts rename to web/projects/shared/src/components/markdown/markdown.component.ts diff --git a/frontend/projects/shared/src/components/text-spinner/text-spinner.component.html b/web/projects/shared/src/components/text-spinner/text-spinner.component.html similarity index 100% rename from frontend/projects/shared/src/components/text-spinner/text-spinner.component.html rename to web/projects/shared/src/components/text-spinner/text-spinner.component.html diff --git a/frontend/projects/shared/src/components/text-spinner/text-spinner.component.module.ts b/web/projects/shared/src/components/text-spinner/text-spinner.component.module.ts similarity index 100% rename from frontend/projects/shared/src/components/text-spinner/text-spinner.component.module.ts rename to web/projects/shared/src/components/text-spinner/text-spinner.component.module.ts diff --git a/frontend/projects/shared/src/components/text-spinner/text-spinner.component.scss b/web/projects/shared/src/components/text-spinner/text-spinner.component.scss similarity index 100% rename from frontend/projects/shared/src/components/text-spinner/text-spinner.component.scss rename to web/projects/shared/src/components/text-spinner/text-spinner.component.scss diff --git a/frontend/projects/shared/src/components/text-spinner/text-spinner.component.ts b/web/projects/shared/src/components/text-spinner/text-spinner.component.ts similarity index 100% rename from frontend/projects/shared/src/components/text-spinner/text-spinner.component.ts rename to web/projects/shared/src/components/text-spinner/text-spinner.component.ts diff --git a/frontend/projects/shared/src/components/ticker/ticker.component.scss b/web/projects/shared/src/components/ticker/ticker.component.scss similarity index 100% rename from frontend/projects/shared/src/components/ticker/ticker.component.scss rename to web/projects/shared/src/components/ticker/ticker.component.scss diff --git a/frontend/projects/shared/src/components/ticker/ticker.component.ts b/web/projects/shared/src/components/ticker/ticker.component.ts similarity index 100% rename from frontend/projects/shared/src/components/ticker/ticker.component.ts rename to web/projects/shared/src/components/ticker/ticker.component.ts diff --git a/frontend/projects/shared/src/components/ticker/ticker.module.ts b/web/projects/shared/src/components/ticker/ticker.module.ts similarity index 100% rename from frontend/projects/shared/src/components/ticker/ticker.module.ts rename to web/projects/shared/src/components/ticker/ticker.module.ts diff --git a/frontend/projects/shared/src/components/toast/toast-button.directive.ts b/web/projects/shared/src/components/toast/toast-button.directive.ts similarity index 100% rename from frontend/projects/shared/src/components/toast/toast-button.directive.ts rename to web/projects/shared/src/components/toast/toast-button.directive.ts diff --git a/frontend/projects/shared/src/components/toast/toast.component.ts b/web/projects/shared/src/components/toast/toast.component.ts similarity index 100% rename from frontend/projects/shared/src/components/toast/toast.component.ts rename to web/projects/shared/src/components/toast/toast.component.ts diff --git a/frontend/projects/shared/src/components/toast/toast.module.ts b/web/projects/shared/src/components/toast/toast.module.ts similarity index 100% rename from frontend/projects/shared/src/components/toast/toast.module.ts rename to web/projects/shared/src/components/toast/toast.module.ts diff --git a/frontend/projects/shared/src/directives/enter/enter.directive.ts b/web/projects/shared/src/directives/enter/enter.directive.ts similarity index 100% rename from frontend/projects/shared/src/directives/enter/enter.directive.ts rename to web/projects/shared/src/directives/enter/enter.directive.ts diff --git a/frontend/projects/shared/src/directives/enter/enter.module.ts b/web/projects/shared/src/directives/enter/enter.module.ts similarity index 100% rename from frontend/projects/shared/src/directives/enter/enter.module.ts rename to web/projects/shared/src/directives/enter/enter.module.ts diff --git a/frontend/projects/shared/src/directives/responsive-col/responsive-col-viewport.directive.ts b/web/projects/shared/src/directives/responsive-col/responsive-col-viewport.directive.ts similarity index 100% rename from frontend/projects/shared/src/directives/responsive-col/responsive-col-viewport.directive.ts rename to web/projects/shared/src/directives/responsive-col/responsive-col-viewport.directive.ts diff --git a/frontend/projects/shared/src/directives/responsive-col/responsive-col.directive.ts b/web/projects/shared/src/directives/responsive-col/responsive-col.directive.ts similarity index 100% rename from frontend/projects/shared/src/directives/responsive-col/responsive-col.directive.ts rename to web/projects/shared/src/directives/responsive-col/responsive-col.directive.ts diff --git a/frontend/projects/shared/src/directives/responsive-col/responsive-col.module.ts b/web/projects/shared/src/directives/responsive-col/responsive-col.module.ts similarity index 100% rename from frontend/projects/shared/src/directives/responsive-col/responsive-col.module.ts rename to web/projects/shared/src/directives/responsive-col/responsive-col.module.ts diff --git a/frontend/projects/shared/src/directives/safe-links/safe-links.directive.ts b/web/projects/shared/src/directives/safe-links/safe-links.directive.ts similarity index 100% rename from frontend/projects/shared/src/directives/safe-links/safe-links.directive.ts rename to web/projects/shared/src/directives/safe-links/safe-links.directive.ts diff --git a/frontend/projects/shared/src/directives/safe-links/safe-links.module.ts b/web/projects/shared/src/directives/safe-links/safe-links.module.ts similarity index 100% rename from frontend/projects/shared/src/directives/safe-links/safe-links.module.ts rename to web/projects/shared/src/directives/safe-links/safe-links.module.ts diff --git a/frontend/projects/shared/src/mocks/get-setup-status.ts b/web/projects/shared/src/mocks/get-setup-status.ts similarity index 100% rename from frontend/projects/shared/src/mocks/get-setup-status.ts rename to web/projects/shared/src/mocks/get-setup-status.ts diff --git a/frontend/projects/shared/src/pipes/emver/emver.module.ts b/web/projects/shared/src/pipes/emver/emver.module.ts similarity index 100% rename from frontend/projects/shared/src/pipes/emver/emver.module.ts rename to web/projects/shared/src/pipes/emver/emver.module.ts diff --git a/frontend/projects/shared/src/pipes/emver/emver.pipe.ts b/web/projects/shared/src/pipes/emver/emver.pipe.ts similarity index 100% rename from frontend/projects/shared/src/pipes/emver/emver.pipe.ts rename to web/projects/shared/src/pipes/emver/emver.pipe.ts diff --git a/frontend/projects/shared/src/pipes/guid/guid.module.ts b/web/projects/shared/src/pipes/guid/guid.module.ts similarity index 100% rename from frontend/projects/shared/src/pipes/guid/guid.module.ts rename to web/projects/shared/src/pipes/guid/guid.module.ts diff --git a/frontend/projects/shared/src/pipes/guid/guid.pipe.ts b/web/projects/shared/src/pipes/guid/guid.pipe.ts similarity index 100% rename from frontend/projects/shared/src/pipes/guid/guid.pipe.ts rename to web/projects/shared/src/pipes/guid/guid.pipe.ts diff --git a/frontend/projects/shared/src/pipes/markdown/markdown.module.ts b/web/projects/shared/src/pipes/markdown/markdown.module.ts similarity index 100% rename from frontend/projects/shared/src/pipes/markdown/markdown.module.ts rename to web/projects/shared/src/pipes/markdown/markdown.module.ts diff --git a/frontend/projects/shared/src/pipes/markdown/markdown.pipe.ts b/web/projects/shared/src/pipes/markdown/markdown.pipe.ts similarity index 100% rename from frontend/projects/shared/src/pipes/markdown/markdown.pipe.ts rename to web/projects/shared/src/pipes/markdown/markdown.pipe.ts diff --git a/frontend/projects/shared/src/pipes/shared/empty.pipe.ts b/web/projects/shared/src/pipes/shared/empty.pipe.ts similarity index 100% rename from frontend/projects/shared/src/pipes/shared/empty.pipe.ts rename to web/projects/shared/src/pipes/shared/empty.pipe.ts diff --git a/frontend/projects/shared/src/pipes/shared/includes.pipe.ts b/web/projects/shared/src/pipes/shared/includes.pipe.ts similarity index 100% rename from frontend/projects/shared/src/pipes/shared/includes.pipe.ts rename to web/projects/shared/src/pipes/shared/includes.pipe.ts diff --git a/frontend/projects/shared/src/pipes/shared/shared.module.ts b/web/projects/shared/src/pipes/shared/shared.module.ts similarity index 100% rename from frontend/projects/shared/src/pipes/shared/shared.module.ts rename to web/projects/shared/src/pipes/shared/shared.module.ts diff --git a/frontend/projects/shared/src/pipes/shared/trust.pipe.ts b/web/projects/shared/src/pipes/shared/trust.pipe.ts similarity index 100% rename from frontend/projects/shared/src/pipes/shared/trust.pipe.ts rename to web/projects/shared/src/pipes/shared/trust.pipe.ts diff --git a/frontend/projects/shared/src/pipes/unit-conversion/unit-conversion.module.ts b/web/projects/shared/src/pipes/unit-conversion/unit-conversion.module.ts similarity index 100% rename from frontend/projects/shared/src/pipes/unit-conversion/unit-conversion.module.ts rename to web/projects/shared/src/pipes/unit-conversion/unit-conversion.module.ts diff --git a/frontend/projects/shared/src/pipes/unit-conversion/unit-conversion.pipe.ts b/web/projects/shared/src/pipes/unit-conversion/unit-conversion.pipe.ts similarity index 100% rename from frontend/projects/shared/src/pipes/unit-conversion/unit-conversion.pipe.ts rename to web/projects/shared/src/pipes/unit-conversion/unit-conversion.pipe.ts diff --git a/frontend/projects/shared/src/public-api.ts b/web/projects/shared/src/public-api.ts similarity index 100% rename from frontend/projects/shared/src/public-api.ts rename to web/projects/shared/src/public-api.ts diff --git a/frontend/projects/shared/src/services/download-html.service.ts b/web/projects/shared/src/services/download-html.service.ts similarity index 100% rename from frontend/projects/shared/src/services/download-html.service.ts rename to web/projects/shared/src/services/download-html.service.ts diff --git a/frontend/projects/shared/src/services/emver.service.ts b/web/projects/shared/src/services/emver.service.ts similarity index 100% rename from frontend/projects/shared/src/services/emver.service.ts rename to web/projects/shared/src/services/emver.service.ts diff --git a/frontend/projects/shared/src/services/error-toast.service.ts b/web/projects/shared/src/services/error-toast.service.ts similarity index 100% rename from frontend/projects/shared/src/services/error-toast.service.ts rename to web/projects/shared/src/services/error-toast.service.ts diff --git a/frontend/projects/shared/src/services/error.service.ts b/web/projects/shared/src/services/error.service.ts similarity index 100% rename from frontend/projects/shared/src/services/error.service.ts rename to web/projects/shared/src/services/error.service.ts diff --git a/frontend/projects/shared/src/services/http.service.ts b/web/projects/shared/src/services/http.service.ts similarity index 100% rename from frontend/projects/shared/src/services/http.service.ts rename to web/projects/shared/src/services/http.service.ts diff --git a/frontend/projects/shared/src/services/setup-logs.service.ts b/web/projects/shared/src/services/setup-logs.service.ts similarity index 100% rename from frontend/projects/shared/src/services/setup-logs.service.ts rename to web/projects/shared/src/services/setup-logs.service.ts diff --git a/frontend/projects/shared/src/services/setup.service.ts b/web/projects/shared/src/services/setup.service.ts similarity index 100% rename from frontend/projects/shared/src/services/setup.service.ts rename to web/projects/shared/src/services/setup.service.ts diff --git a/frontend/projects/shared/src/themes/dark-theme/dark-theme.component.scss b/web/projects/shared/src/themes/dark-theme/dark-theme.component.scss similarity index 100% rename from frontend/projects/shared/src/themes/dark-theme/dark-theme.component.scss rename to web/projects/shared/src/themes/dark-theme/dark-theme.component.scss diff --git a/frontend/projects/shared/src/themes/dark-theme/dark-theme.component.ts b/web/projects/shared/src/themes/dark-theme/dark-theme.component.ts similarity index 100% rename from frontend/projects/shared/src/themes/dark-theme/dark-theme.component.ts rename to web/projects/shared/src/themes/dark-theme/dark-theme.component.ts diff --git a/frontend/projects/shared/src/themes/dark-theme/dark-theme.module.ts b/web/projects/shared/src/themes/dark-theme/dark-theme.module.ts similarity index 100% rename from frontend/projects/shared/src/themes/dark-theme/dark-theme.module.ts rename to web/projects/shared/src/themes/dark-theme/dark-theme.module.ts diff --git a/frontend/projects/shared/src/themes/light-theme/light-theme.component.scss b/web/projects/shared/src/themes/light-theme/light-theme.component.scss similarity index 100% rename from frontend/projects/shared/src/themes/light-theme/light-theme.component.scss rename to web/projects/shared/src/themes/light-theme/light-theme.component.scss diff --git a/frontend/projects/shared/src/themes/light-theme/light-theme.component.ts b/web/projects/shared/src/themes/light-theme/light-theme.component.ts similarity index 100% rename from frontend/projects/shared/src/themes/light-theme/light-theme.component.ts rename to web/projects/shared/src/themes/light-theme/light-theme.component.ts diff --git a/frontend/projects/shared/src/themes/light-theme/light-theme.module.ts b/web/projects/shared/src/themes/light-theme/light-theme.module.ts similarity index 100% rename from frontend/projects/shared/src/themes/light-theme/light-theme.module.ts rename to web/projects/shared/src/themes/light-theme/light-theme.module.ts diff --git a/frontend/projects/shared/src/tokens/relative-url.ts b/web/projects/shared/src/tokens/relative-url.ts similarity index 100% rename from frontend/projects/shared/src/tokens/relative-url.ts rename to web/projects/shared/src/tokens/relative-url.ts diff --git a/frontend/projects/shared/src/tokens/theme.ts b/web/projects/shared/src/tokens/theme.ts similarity index 100% rename from frontend/projects/shared/src/tokens/theme.ts rename to web/projects/shared/src/tokens/theme.ts diff --git a/frontend/projects/shared/src/types/api.ts b/web/projects/shared/src/types/api.ts similarity index 100% rename from frontend/projects/shared/src/types/api.ts rename to web/projects/shared/src/types/api.ts diff --git a/frontend/projects/shared/src/types/constructor.ts b/web/projects/shared/src/types/constructor.ts similarity index 100% rename from frontend/projects/shared/src/types/constructor.ts rename to web/projects/shared/src/types/constructor.ts diff --git a/frontend/projects/shared/src/types/http.types.ts b/web/projects/shared/src/types/http.types.ts similarity index 100% rename from frontend/projects/shared/src/types/http.types.ts rename to web/projects/shared/src/types/http.types.ts diff --git a/frontend/projects/shared/src/types/rpc.types.ts b/web/projects/shared/src/types/rpc.types.ts similarity index 100% rename from frontend/projects/shared/src/types/rpc.types.ts rename to web/projects/shared/src/types/rpc.types.ts diff --git a/frontend/projects/shared/src/types/url.ts b/web/projects/shared/src/types/url.ts similarity index 100% rename from frontend/projects/shared/src/types/url.ts rename to web/projects/shared/src/types/url.ts diff --git a/frontend/projects/shared/src/types/workspace-config.ts b/web/projects/shared/src/types/workspace-config.ts similarity index 100% rename from frontend/projects/shared/src/types/workspace-config.ts rename to web/projects/shared/src/types/workspace-config.ts diff --git a/frontend/projects/shared/src/util/base-64.ts b/web/projects/shared/src/util/base-64.ts similarity index 100% rename from frontend/projects/shared/src/util/base-64.ts rename to web/projects/shared/src/util/base-64.ts diff --git a/frontend/projects/shared/src/util/copy-to-clipboard.ts b/web/projects/shared/src/util/copy-to-clipboard.ts similarity index 100% rename from frontend/projects/shared/src/util/copy-to-clipboard.ts rename to web/projects/shared/src/util/copy-to-clipboard.ts diff --git a/frontend/projects/shared/src/util/get-new-entries.ts b/web/projects/shared/src/util/get-new-entries.ts similarity index 100% rename from frontend/projects/shared/src/util/get-new-entries.ts rename to web/projects/shared/src/util/get-new-entries.ts diff --git a/frontend/projects/shared/src/util/get-pkg-id.ts b/web/projects/shared/src/util/get-pkg-id.ts similarity index 100% rename from frontend/projects/shared/src/util/get-pkg-id.ts rename to web/projects/shared/src/util/get-pkg-id.ts diff --git a/frontend/projects/shared/src/util/invert.ts b/web/projects/shared/src/util/invert.ts similarity index 100% rename from frontend/projects/shared/src/util/invert.ts rename to web/projects/shared/src/util/invert.ts diff --git a/frontend/projects/shared/src/util/misc.util.ts b/web/projects/shared/src/util/misc.util.ts similarity index 100% rename from frontend/projects/shared/src/util/misc.util.ts rename to web/projects/shared/src/util/misc.util.ts diff --git a/frontend/projects/shared/src/util/rpc.util.ts b/web/projects/shared/src/util/rpc.util.ts similarity index 100% rename from frontend/projects/shared/src/util/rpc.util.ts rename to web/projects/shared/src/util/rpc.util.ts diff --git a/frontend/projects/shared/src/util/to-local-iso-string.ts b/web/projects/shared/src/util/to-local-iso-string.ts similarity index 100% rename from frontend/projects/shared/src/util/to-local-iso-string.ts rename to web/projects/shared/src/util/to-local-iso-string.ts diff --git a/frontend/projects/shared/src/util/unused.ts b/web/projects/shared/src/util/unused.ts similarity index 100% rename from frontend/projects/shared/src/util/unused.ts rename to web/projects/shared/src/util/unused.ts diff --git a/frontend/projects/shared/styles/global.scss b/web/projects/shared/styles/global.scss similarity index 100% rename from frontend/projects/shared/styles/global.scss rename to web/projects/shared/styles/global.scss diff --git a/frontend/projects/shared/styles/shared.scss b/web/projects/shared/styles/shared.scss similarity index 100% rename from frontend/projects/shared/styles/shared.scss rename to web/projects/shared/styles/shared.scss diff --git a/frontend/projects/shared/styles/variables.scss b/web/projects/shared/styles/variables.scss similarity index 100% rename from frontend/projects/shared/styles/variables.scss rename to web/projects/shared/styles/variables.scss diff --git a/frontend/projects/shared/tsconfig.json b/web/projects/shared/tsconfig.json similarity index 100% rename from frontend/projects/shared/tsconfig.json rename to web/projects/shared/tsconfig.json diff --git a/frontend/projects/ui/ngsw-config.json b/web/projects/ui/ngsw-config.json similarity index 100% rename from frontend/projects/ui/ngsw-config.json rename to web/projects/ui/ngsw-config.json diff --git a/web/projects/ui/src/app/app-routing.module.ts b/web/projects/ui/src/app/app-routing.module.ts new file mode 100644 index 000000000..b1b79c05d --- /dev/null +++ b/web/projects/ui/src/app/app-routing.module.ts @@ -0,0 +1,87 @@ +import { NgModule } from '@angular/core' +import { PreloadAllModules, RouterModule, Routes } from '@angular/router' +import { AuthGuard } from './guards/auth.guard' +import { UnauthGuard } from './guards/unauth.guard' + +const routes: Routes = [ + { + redirectTo: 'services', + pathMatch: 'full', + path: '', + }, + { + path: 'login', + canActivate: [UnauthGuard], + loadChildren: () => + import('./pages/login/login.module').then(m => m.LoginPageModule), + }, + { + path: 'home', + canActivate: [AuthGuard], + loadChildren: () => + import('./pages/home/home.module').then(m => m.HomePageModule), + }, + { + path: 'system', + canActivate: [AuthGuard], + canActivateChild: [AuthGuard], + loadChildren: () => + import('./pages/server-routes/server-routing.module').then( + m => m.ServerRoutingModule, + ), + }, + { + path: 'updates', + canActivate: [AuthGuard], + canActivateChild: [AuthGuard], + loadChildren: () => + import('./pages/updates/updates.module').then(m => m.UpdatesPageModule), + }, + { + path: 'marketplace', + canActivate: [AuthGuard], + canActivateChild: [AuthGuard], + loadChildren: () => + import('./pages/marketplace-routes/marketplace-routing.module').then( + m => m.MarketplaceRoutingModule, + ), + }, + { + path: 'notifications', + canActivate: [AuthGuard], + loadChildren: () => + import('./pages/notifications/notifications.module').then( + m => m.NotificationsPageModule, + ), + }, + { + path: 'services', + canActivate: [AuthGuard], + canActivateChild: [AuthGuard], + loadChildren: () => + import('./pages/apps-routes/apps-routing.module').then( + m => m.AppsRoutingModule, + ), + }, + { + path: 'developer', + canActivate: [AuthGuard], + canActivateChild: [AuthGuard], + loadChildren: () => + import('./pages/developer-routes/developer-routing.module').then( + m => m.DeveloperRoutingModule, + ), + }, +] + +@NgModule({ + imports: [ + RouterModule.forRoot(routes, { + scrollPositionRestoration: 'enabled', + preloadingStrategy: PreloadAllModules, + initialNavigation: 'disabled', + }), + ], + exports: [RouterModule], +}) +export class AppRoutingModule {} diff --git a/frontend/projects/ui/src/app/app.component.html b/web/projects/ui/src/app/app.component.html similarity index 100% rename from frontend/projects/ui/src/app/app.component.html rename to web/projects/ui/src/app/app.component.html diff --git a/frontend/projects/ui/src/app/app.component.scss b/web/projects/ui/src/app/app.component.scss similarity index 100% rename from frontend/projects/ui/src/app/app.component.scss rename to web/projects/ui/src/app/app.component.scss diff --git a/frontend/projects/ui/src/app/app.component.ts b/web/projects/ui/src/app/app.component.ts similarity index 100% rename from frontend/projects/ui/src/app/app.component.ts rename to web/projects/ui/src/app/app.component.ts diff --git a/frontend/projects/ui/src/app/app.module.ts b/web/projects/ui/src/app/app.module.ts similarity index 100% rename from frontend/projects/ui/src/app/app.module.ts rename to web/projects/ui/src/app/app.module.ts diff --git a/frontend/projects/ui/src/app/app.providers.ts b/web/projects/ui/src/app/app.providers.ts similarity index 100% rename from frontend/projects/ui/src/app/app.providers.ts rename to web/projects/ui/src/app/app.providers.ts diff --git a/frontend/projects/ui/src/app/app/connection-bar/connection-bar.component.html b/web/projects/ui/src/app/app/connection-bar/connection-bar.component.html similarity index 100% rename from frontend/projects/ui/src/app/app/connection-bar/connection-bar.component.html rename to web/projects/ui/src/app/app/connection-bar/connection-bar.component.html diff --git a/frontend/projects/ui/src/app/app/connection-bar/connection-bar.component.module.ts b/web/projects/ui/src/app/app/connection-bar/connection-bar.component.module.ts similarity index 100% rename from frontend/projects/ui/src/app/app/connection-bar/connection-bar.component.module.ts rename to web/projects/ui/src/app/app/connection-bar/connection-bar.component.module.ts diff --git a/frontend/projects/ui/src/app/app/connection-bar/connection-bar.component.scss b/web/projects/ui/src/app/app/connection-bar/connection-bar.component.scss similarity index 100% rename from frontend/projects/ui/src/app/app/connection-bar/connection-bar.component.scss rename to web/projects/ui/src/app/app/connection-bar/connection-bar.component.scss diff --git a/frontend/projects/ui/src/app/app/connection-bar/connection-bar.component.ts b/web/projects/ui/src/app/app/connection-bar/connection-bar.component.ts similarity index 100% rename from frontend/projects/ui/src/app/app/connection-bar/connection-bar.component.ts rename to web/projects/ui/src/app/app/connection-bar/connection-bar.component.ts diff --git a/frontend/projects/ui/src/app/app/footer/footer.component.html b/web/projects/ui/src/app/app/footer/footer.component.html similarity index 86% rename from frontend/projects/ui/src/app/app/footer/footer.component.html rename to web/projects/ui/src/app/app/footer/footer.component.html index 306ceca67..0d5987a8e 100644 --- a/frontend/projects/ui/src/app/app/footer/footer.component.html +++ b/web/projects/ui/src/app/app/footer/footer.component.html @@ -7,10 +7,9 @@ - Downloading: - {{ getProgress(progress.size, progress.downloaded) }}% + + Downloading: {{ getProgress(progress.size, progress.downloaded) }}% + + + Execution Complete + + + + + + + + + +

{{ actionRes.message }}

+ +
+
+ +
+ +

{{ actionRes.value }}

+ + {{ actionRes.value }} + + + + +
+
diff --git a/web/projects/ui/src/app/modals/action-success/action-success.page.scss b/web/projects/ui/src/app/modals/action-success/action-success.page.scss new file mode 100644 index 000000000..e69de29bb diff --git a/web/projects/ui/src/app/modals/action-success/action-success.page.ts b/web/projects/ui/src/app/modals/action-success/action-success.page.ts new file mode 100644 index 000000000..48adb138a --- /dev/null +++ b/web/projects/ui/src/app/modals/action-success/action-success.page.ts @@ -0,0 +1,38 @@ +import { Component, Input } from '@angular/core' +import { ModalController, ToastController } from '@ionic/angular' +import { ActionResponse } from 'src/app/services/api/api.types' +import { copyToClipboard } from '@start9labs/shared' + +@Component({ + selector: 'action-success', + templateUrl: './action-success.page.html', +}) +export class ActionSuccessPage { + @Input() + actionRes!: ActionResponse + + constructor( + private readonly modalCtrl: ModalController, + private readonly toastCtrl: ToastController, + ) {} + + async copy(address: string) { + let message = '' + await copyToClipboard(address || '').then(success => { + message = success + ? 'Copied to clipboard!' + : 'Failed to copy to clipboard.' + }) + + const toast = await this.toastCtrl.create({ + header: message, + position: 'bottom', + duration: 1000, + }) + await toast.present() + } + + async dismiss() { + return this.modalCtrl.dismiss() + } +} diff --git a/web/projects/ui/src/app/modals/app-config/app-config.module.ts b/web/projects/ui/src/app/modals/app-config/app-config.module.ts new file mode 100644 index 000000000..fde422826 --- /dev/null +++ b/web/projects/ui/src/app/modals/app-config/app-config.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { FormsModule, ReactiveFormsModule } from '@angular/forms' +import { IonicModule } from '@ionic/angular' +import { AppConfigPage } from './app-config.page' +import { TextSpinnerComponentModule } from '@start9labs/shared' +import { FormObjectComponentModule } from 'src/app/components/form-object/form-object.component.module' + +@NgModule({ + declarations: [AppConfigPage], + imports: [ + CommonModule, + FormsModule, + IonicModule, + TextSpinnerComponentModule, + FormObjectComponentModule, + ReactiveFormsModule, + ], + exports: [AppConfigPage], +}) +export class AppConfigPageModule {} diff --git a/web/projects/ui/src/app/modals/app-config/app-config.page.html b/web/projects/ui/src/app/modals/app-config/app-config.page.html new file mode 100644 index 000000000..49eec5f5f --- /dev/null +++ b/web/projects/ui/src/app/modals/app-config/app-config.page.html @@ -0,0 +1,149 @@ + + + Config + + + + + + + + + + + + + + + + + {{ loadingError }} + + + + + + +

+ + {{ pkg.manifest.title }} has been automatically configured with + recommended defaults. Make whatever changes you want, then click + "Save". + +

+
+ +

+ + New config options! To accept the default values, click "Save". + You may also customize these new options below. + +

+
+
+ + + + +

+ + + {{ pkg.manifest.title }} + +

+

+ + The following modifications have been made to {{ + pkg.manifest.title }} to satisfy {{ dependentInfo.title }}: +

    +
  • +
+ To accept these modifications, click "Save". + +

+
+
+ + + + +

+ No config options for {{ pkg.manifest.title }} {{ + pkg.manifest.version }}. +

+
+
+ + +
+ +
+
+
+
+ + + + + + + + Reset Defaults + + + + + Save + + + Close + + + + + diff --git a/web/projects/ui/src/app/modals/app-config/app-config.page.scss b/web/projects/ui/src/app/modals/app-config/app-config.page.scss new file mode 100644 index 000000000..e568528a8 --- /dev/null +++ b/web/projects/ui/src/app/modals/app-config/app-config.page.scss @@ -0,0 +1,12 @@ +.notifier-item { + margin: 12px; + margin-top: 0px; + border-radius: 12px; + // kills the lines + --border-width: 0; + --inner-border-width: 0; +} + +.header-details { + font-size: 20px; +} \ No newline at end of file diff --git a/web/projects/ui/src/app/modals/app-config/app-config.page.ts b/web/projects/ui/src/app/modals/app-config/app-config.page.ts new file mode 100644 index 000000000..35388b36c --- /dev/null +++ b/web/projects/ui/src/app/modals/app-config/app-config.page.ts @@ -0,0 +1,344 @@ +import { Component, Input } from '@angular/core' +import { + AlertController, + ModalController, + LoadingController, + IonicSafeString, +} from '@ionic/angular' +import { ApiService } from 'src/app/services/api/embassy-api.service' +import { + ErrorToastService, + getErrorMessage, + isEmptyObject, + isObject, +} from '@start9labs/shared' +import { DependentInfo } from 'src/app/types/dependent-info' +import { ConfigSpec } from 'src/app/pkg-config/config-types' +import { + DataModel, + PackageDataEntry, +} from 'src/app/services/patch-db/data-model' +import { PatchDB } from 'patch-db-client' +import { UntypedFormGroup } from '@angular/forms' +import { + convertValuesRecursive, + FormService, +} from 'src/app/services/form.service' +import { compare, Operation, getValueByPointer } from 'fast-json-patch' +import { hasCurrentDeps } from 'src/app/util/has-deps' +import { getAllPackages, getPackage } from 'src/app/util/get-package-data' +import { Breakages } from 'src/app/services/api/api.types' + +@Component({ + selector: 'app-config', + templateUrl: './app-config.page.html', + styleUrls: ['./app-config.page.scss'], +}) +export class AppConfigPage { + @Input() pkgId!: string + + @Input() dependentInfo?: DependentInfo + + pkg!: PackageDataEntry + loadingText = '' + + configSpec?: ConfigSpec + configForm?: UntypedFormGroup + + original?: object // only if existing config + diff?: string[] // only if dependent info + + loading = true + hasNewOptions = false + saving = false + loadingError: string | IonicSafeString = '' + + hasOptions = false + + constructor( + private readonly embassyApi: ApiService, + private readonly errToast: ErrorToastService, + private readonly loadingCtrl: LoadingController, + private readonly alertCtrl: AlertController, + private readonly modalCtrl: ModalController, + private readonly formService: FormService, + private readonly patch: PatchDB, + ) {} + + async ngOnInit() { + try { + const pkg = await getPackage(this.patch, this.pkgId) + if (!pkg) return + this.pkg = pkg + + if (!this.pkg.manifest.config) return + + let newConfig: object | undefined + let patch: Operation[] | undefined + + if (this.dependentInfo) { + this.loadingText = `Setting properties to accommodate ${this.dependentInfo.title}` + const { + 'old-config': oc, + 'new-config': nc, + spec: s, + } = await this.embassyApi.dryConfigureDependency({ + 'dependency-id': this.pkgId, + 'dependent-id': this.dependentInfo.id, + }) + this.original = oc + newConfig = nc + this.configSpec = s + patch = compare(this.original, newConfig) + } else { + this.loadingText = 'Loading Config' + const { config: c, spec: s } = await this.embassyApi.getPackageConfig({ + id: this.pkgId, + }) + this.original = c + this.configSpec = s + } + + this.configForm = this.formService.createForm( + this.configSpec, + newConfig || this.original, + ) + + this.hasOptions = !!Object.values(this.configSpec).find( + valSpec => valSpec.type !== 'pointer', + ) + + if (patch) { + this.diff = this.getDiff(patch) + this.markDirty(patch) + } + } catch (e: any) { + this.loadingError = getErrorMessage(e) + } finally { + this.loading = false + } + } + + resetDefaults() { + this.configForm = this.formService.createForm(this.configSpec!) + const patch = compare(this.original || {}, this.configForm.value) + this.markDirty(patch) + } + + async dismiss() { + if (this.configForm?.dirty) { + this.presentAlertUnsaved() + } else { + this.modalCtrl.dismiss() + } + } + + async tryConfigure() { + convertValuesRecursive(this.configSpec!, this.configForm!) + + if (this.configForm!.invalid) { + document + .getElementsByClassName('validation-error')[0] + ?.scrollIntoView({ behavior: 'smooth' }) + return + } + + this.saving = true + + if (hasCurrentDeps(this.pkg)) { + this.dryConfigure() + } else { + this.configure() + } + } + + private async dryConfigure() { + const loader = await this.loadingCtrl.create({ + message: 'Checking dependent services...', + }) + await loader.present() + + try { + const breakages = await this.embassyApi.drySetPackageConfig({ + id: this.pkgId, + config: this.configForm!.value, + }) + + if (isEmptyObject(breakages)) { + this.configure(loader) + } else { + await loader.dismiss() + const proceed = await this.presentAlertBreakages(breakages) + if (proceed) { + this.configure() + } else { + this.saving = false + } + } + } catch (e: any) { + this.errToast.present(e) + this.saving = false + loader.dismiss() + } + } + + private async configure(loader?: HTMLIonLoadingElement) { + const message = 'Saving...' + if (loader) { + loader.message = message + } else { + loader = await this.loadingCtrl.create({ message }) + await loader.present() + } + + try { + await this.embassyApi.setPackageConfig({ + id: this.pkgId, + config: this.configForm!.value, + }) + this.modalCtrl.dismiss() + } catch (e: any) { + this.errToast.present(e) + } finally { + this.saving = false + loader.dismiss() + } + } + + private async presentAlertBreakages(breakages: Breakages): Promise { + let message: string = + 'As a result of this change, the following services will no longer work properly and may crash:
    ' + const localPkgs = await getAllPackages(this.patch) + const bullets = Object.keys(breakages).map(id => { + const title = localPkgs[id].manifest.title + return `
  • ${title}
  • ` + }) + message = `${message}${bullets}
` + + return new Promise(async resolve => { + const alert = await this.alertCtrl.create({ + header: 'Warning', + message, + buttons: [ + { + text: 'Cancel', + role: 'cancel', + handler: () => { + resolve(false) + }, + }, + { + text: 'Continue', + handler: () => { + resolve(true) + }, + cssClass: 'enter-click', + }, + ], + cssClass: 'alert-warning-message', + }) + + await alert.present() + }) + } + + private getDiff(patch: Operation[]): string[] { + return patch.map(op => { + let message: string + switch (op.op) { + case 'add': + message = `Added ${this.getNewValue(op.value)}` + break + case 'remove': + message = `Removed ${this.getOldValue(op.path)}` + break + case 'replace': + message = `Changed from ${this.getOldValue( + op.path, + )} to ${this.getNewValue(op.value)}` + break + default: + message = `Unknown operation` + } + + let displayPath: string + + const arrPath = op.path + .substring(1) + .split('/') + .map(node => { + const num = Number(node) + return isNaN(num) ? node : num + }) + + if (typeof arrPath[arrPath.length - 1] === 'number') { + arrPath.pop() + } + + displayPath = arrPath.join(' → ') + + return `${displayPath}: ${message}` + }) + } + + private getOldValue(path: any): string { + const val = getValueByPointer(this.original, path) + if (['string', 'number', 'boolean'].includes(typeof val)) { + return val + } else if (isObject(val)) { + return 'entry' + } else { + return 'list' + } + } + + private getNewValue(val: any): string { + if (['string', 'number', 'boolean'].includes(typeof val)) { + return val + } else if (isObject(val)) { + return 'new entry' + } else { + return 'new list' + } + } + + private markDirty(patch: Operation[]) { + patch.forEach(op => { + const arrPath = op.path + .substring(1) + .split('/') + .map(node => { + const num = Number(node) + return isNaN(num) ? node : num + }) + + if (op.op !== 'remove') this.configForm!.get(arrPath)?.markAsDirty() + + if (typeof arrPath[arrPath.length - 1] === 'number') { + const prevPath = arrPath.slice(0, arrPath.length - 1) + this.configForm!.get(prevPath)?.markAsDirty() + } + }) + } + + private async presentAlertUnsaved() { + const alert = await this.alertCtrl.create({ + header: 'Unsaved Changes', + message: 'You have unsaved changes. Are you sure you want to leave?', + buttons: [ + { + text: 'Cancel', + role: 'cancel', + }, + { + text: `Leave`, + handler: () => { + this.modalCtrl.dismiss() + }, + cssClass: 'enter-click', + }, + ], + }) + await alert.present() + } +} diff --git a/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.module.ts b/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.module.ts new file mode 100644 index 000000000..3cf866171 --- /dev/null +++ b/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' +import { FormsModule } from '@angular/forms' +import { RecoverSelectPage } from './recover-select.page' +import { ToOptionsPipe } from './to-options.pipe' + +@NgModule({ + declarations: [RecoverSelectPage, ToOptionsPipe], + imports: [CommonModule, IonicModule, FormsModule], + exports: [RecoverSelectPage], +}) +export class RecoverSelectPageModule {} diff --git a/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.page.html b/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.page.html new file mode 100644 index 000000000..09a055650 --- /dev/null +++ b/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.page.html @@ -0,0 +1,61 @@ + + + + Select Services to Restore + + + + + + + + + + + + +

{{ option.title }}

+

Version {{ option.version }}

+

Backup made: {{ option.timestamp | date : 'medium' }}

+

+ Ready to restore +

+

+ + Unavailable. {{ option.title }} is already installed. + +

+

+ + Unavailable. Backup was made on a newer version of StartOS. + +

+
+ +
+
+
+ + + + + + Restore Selected + + + + +
diff --git a/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.page.scss b/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.page.scss new file mode 100644 index 000000000..e69de29bb diff --git a/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.page.ts b/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.page.ts new file mode 100644 index 000000000..85989cc45 --- /dev/null +++ b/web/projects/ui/src/app/modals/app-recover-select/app-recover-select.page.ts @@ -0,0 +1,66 @@ +import { Component, Input } from '@angular/core' +import { + LoadingController, + ModalController, + IonicSafeString, +} from '@ionic/angular' +import { getErrorMessage } from '@start9labs/shared' +import { BackupInfo } from 'src/app/services/api/api.types' +import { ApiService } from 'src/app/services/api/embassy-api.service' +import { PatchDB } from 'patch-db-client' +import { AppRecoverOption } from './to-options.pipe' +import { DataModel } from 'src/app/services/patch-db/data-model' +import { take } from 'rxjs' + +@Component({ + selector: 'recover-select', + templateUrl: './recover-select.page.html', + styleUrls: ['./recover-select.page.scss'], +}) +export class RecoverSelectPage { + @Input() targetId!: string + @Input() backupInfo!: BackupInfo + @Input() password!: string + @Input() oldPassword?: string + + readonly packageData$ = this.patch.watch$('package-data').pipe(take(1)) + + hasSelection = false + error: string | IonicSafeString = '' + + constructor( + private readonly modalCtrl: ModalController, + private readonly loadingCtrl: LoadingController, + private readonly embassyApi: ApiService, + private readonly patch: PatchDB, + ) {} + + dismiss() { + this.modalCtrl.dismiss() + } + + handleChange(options: AppRecoverOption[]) { + this.hasSelection = options.some(o => o.checked) + } + + async restore(options: AppRecoverOption[]): Promise { + const ids = options.filter(({ checked }) => !!checked).map(({ id }) => id) + const loader = await this.loadingCtrl.create({ + message: 'Initializing...', + }) + await loader.present() + + try { + await this.embassyApi.restorePackages({ + ids, + 'target-id': this.targetId, + password: this.password, + }) + this.modalCtrl.dismiss(undefined, 'success') + } catch (e: any) { + this.error = getErrorMessage(e) + } finally { + loader.dismiss() + } + } +} diff --git a/web/projects/ui/src/app/modals/app-recover-select/to-options.pipe.ts b/web/projects/ui/src/app/modals/app-recover-select/to-options.pipe.ts new file mode 100644 index 000000000..59a5644bb --- /dev/null +++ b/web/projects/ui/src/app/modals/app-recover-select/to-options.pipe.ts @@ -0,0 +1,49 @@ +import { Pipe, PipeTransform } from '@angular/core' +import { Emver } from '@start9labs/shared' +import { map, Observable } from 'rxjs' +import { PackageBackupInfo } from 'src/app/services/api/api.types' +import { ConfigService } from 'src/app/services/config.service' +import { PackageDataEntry } from 'src/app/services/patch-db/data-model' + +export interface AppRecoverOption extends PackageBackupInfo { + id: string + checked: boolean + installed: boolean + 'newer-eos': boolean +} + +@Pipe({ + name: 'toOptions', +}) +export class ToOptionsPipe implements PipeTransform { + constructor( + private readonly config: ConfigService, + private readonly emver: Emver, + ) {} + + transform( + packageData$: Observable>, + packageBackups: Record = {}, + ): Observable { + return packageData$.pipe( + map(packageData => + Object.keys(packageBackups) + .map(id => ({ + ...packageBackups[id], + id, + installed: !!packageData[id], + checked: false, + 'newer-eos': this.compare(packageBackups[id]['os-version']), + })) + .sort((a, b) => + b.title.toLowerCase() > a.title.toLowerCase() ? -1 : 1, + ), + ), + ) + } + + private compare(version: string): boolean { + // checks to see if backup was made on a newer version of eOS + return this.emver.compare(version, this.config.version) === 1 + } +} diff --git a/web/projects/ui/src/app/modals/backup-report/backup-report.module.ts b/web/projects/ui/src/app/modals/backup-report/backup-report.module.ts new file mode 100644 index 000000000..f21ff0918 --- /dev/null +++ b/web/projects/ui/src/app/modals/backup-report/backup-report.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' +import { BackupReportPage } from './backup-report.page' + +@NgModule({ + declarations: [BackupReportPage], + imports: [CommonModule, IonicModule], + exports: [BackupReportPage], +}) +export class BackupReportPageModule {} diff --git a/web/projects/ui/src/app/modals/backup-report/backup-report.page.html b/web/projects/ui/src/app/modals/backup-report/backup-report.page.html new file mode 100644 index 000000000..4ecf064d9 --- /dev/null +++ b/web/projects/ui/src/app/modals/backup-report/backup-report.page.html @@ -0,0 +1,44 @@ + + + Backup Report + + + + + + + + + + + + Completed: {{ timestamp | date : 'medium' }} + + + +

System data

+

{{ system.result }}

+
+ +
+ + +

{{ pkg.key }}

+

+ + {{ pkg.value.error ? 'Failed: ' + pkg.value.error : 'Succeeded' }} + +

+
+ +
+
+
diff --git a/web/projects/ui/src/app/modals/backup-report/backup-report.page.scss b/web/projects/ui/src/app/modals/backup-report/backup-report.page.scss new file mode 100644 index 000000000..e69de29bb diff --git a/web/projects/ui/src/app/modals/backup-report/backup-report.page.ts b/web/projects/ui/src/app/modals/backup-report/backup-report.page.ts new file mode 100644 index 000000000..7434f5152 --- /dev/null +++ b/web/projects/ui/src/app/modals/backup-report/backup-report.page.ts @@ -0,0 +1,46 @@ +import { Component, Input } from '@angular/core' +import { ModalController } from '@ionic/angular' +import { BackupReport } from 'src/app/services/api/api.types' + +@Component({ + selector: 'backup-report', + templateUrl: './backup-report.page.html', +}) +export class BackupReportPage { + @Input() report!: BackupReport + @Input() timestamp!: string + + system!: { + result: string + icon: 'remove' | 'remove-circle-outline' | 'checkmark' + color: 'dark' | 'danger' | 'success' + } + + constructor(private readonly modalCtrl: ModalController) {} + + ngOnInit() { + if (!this.report.server.attempted) { + this.system = { + result: 'Not Attempted', + icon: 'remove', + color: 'dark', + } + } else if (this.report.server.error) { + this.system = { + result: `Failed: ${this.report.server.error}`, + icon: 'remove-circle-outline', + color: 'danger', + } + } else { + this.system = { + result: 'Succeeded', + icon: 'checkmark', + color: 'success', + } + } + } + + async dismiss() { + return this.modalCtrl.dismiss(true) + } +} diff --git a/web/projects/ui/src/app/modals/backup-select/backup-select.module.ts b/web/projects/ui/src/app/modals/backup-select/backup-select.module.ts new file mode 100644 index 000000000..be840eff2 --- /dev/null +++ b/web/projects/ui/src/app/modals/backup-select/backup-select.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' +import { BackupSelectPage } from './backup-select.page' +import { FormsModule } from '@angular/forms' + +@NgModule({ + declarations: [BackupSelectPage], + imports: [CommonModule, IonicModule, FormsModule], + exports: [BackupSelectPage], +}) +export class BackupSelectPageModule {} diff --git a/web/projects/ui/src/app/modals/backup-select/backup-select.page.html b/web/projects/ui/src/app/modals/backup-select/backup-select.page.html new file mode 100644 index 000000000..457152a45 --- /dev/null +++ b/web/projects/ui/src/app/modals/backup-select/backup-select.page.html @@ -0,0 +1,57 @@ + + + Select Services to Back Up + + + + + + + + + + + + + + + {{ selectAll ? 'Select All' : 'Deselect All' }} + + + + + + + + +

{{ pkg.title }}

+
+ +
+
+
+ +

No services installed!

+
+
+ + + + + + {{ btnText }} + + + + diff --git a/web/projects/ui/src/app/modals/backup-select/backup-select.page.scss b/web/projects/ui/src/app/modals/backup-select/backup-select.page.scss new file mode 100644 index 000000000..854c0ba4e --- /dev/null +++ b/web/projects/ui/src/app/modals/backup-select/backup-select.page.scss @@ -0,0 +1,5 @@ +.center { + display: flex; + align-items: center; + justify-content: center; +} \ No newline at end of file diff --git a/web/projects/ui/src/app/modals/backup-select/backup-select.page.ts b/web/projects/ui/src/app/modals/backup-select/backup-select.page.ts new file mode 100644 index 000000000..6c1f84614 --- /dev/null +++ b/web/projects/ui/src/app/modals/backup-select/backup-select.page.ts @@ -0,0 +1,71 @@ +import { Component, Input } from '@angular/core' +import { ModalController } from '@ionic/angular' +import { PatchDB } from 'patch-db-client' +import { firstValueFrom, map } from 'rxjs' +import { DataModel, PackageState } from 'src/app/services/patch-db/data-model' + +@Component({ + selector: 'backup-select', + templateUrl: './backup-select.page.html', + styleUrls: ['./backup-select.page.scss'], +}) +export class BackupSelectPage { + @Input() btnText!: string + @Input() selectedIds: string[] = [] + + hasSelection = false + selectAll = false + pkgs: { + id: string + title: string + icon: string + disabled: boolean + checked: boolean + }[] = [] + + constructor( + private readonly modalCtrl: ModalController, + private readonly patch: PatchDB, + ) {} + + async ngOnInit() { + this.pkgs = await firstValueFrom( + this.patch.watch$('package-data').pipe( + map(pkgs => { + return Object.values(pkgs) + .map(pkg => { + const { id, title } = pkg.manifest + return { + id, + title, + icon: pkg.icon, + disabled: pkg.state !== PackageState.Installed, + checked: this.selectedIds.includes(id), + } + }) + .sort((a, b) => + b.title.toLowerCase() > a.title.toLowerCase() ? -1 : 1, + ) + }), + ), + ) + } + + dismiss() { + this.modalCtrl.dismiss() + } + + async done() { + const pkgIds = this.pkgs.filter(p => p.checked).map(p => p.id) + this.modalCtrl.dismiss(pkgIds) + } + + handleChange() { + this.hasSelection = this.pkgs.some(p => p.checked) + } + + toggleSelectAll() { + this.pkgs.forEach(pkg => (pkg.checked = this.selectAll)) + this.selectAll = !this.selectAll + } +} diff --git a/web/projects/ui/src/app/modals/enum-list/enum-list.module.ts b/web/projects/ui/src/app/modals/enum-list/enum-list.module.ts new file mode 100644 index 000000000..a0acb46d5 --- /dev/null +++ b/web/projects/ui/src/app/modals/enum-list/enum-list.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' +import { EnumListPage } from './enum-list.page' +import { FormsModule } from '@angular/forms' + +@NgModule({ + declarations: [EnumListPage], + imports: [CommonModule, IonicModule, FormsModule], + exports: [EnumListPage], +}) +export class EnumListPageModule {} diff --git a/web/projects/ui/src/app/modals/enum-list/enum-list.page.html b/web/projects/ui/src/app/modals/enum-list/enum-list.page.html new file mode 100644 index 000000000..5cc74ba21 --- /dev/null +++ b/web/projects/ui/src/app/modals/enum-list/enum-list.page.html @@ -0,0 +1,45 @@ + + + {{ spec.name }} + + + + + + + + + + + + + + {{ selectAll ? 'Select All' : 'Deselect All' }} + + + + + {{ spec.spec['value-names'][option.key] }} + + + + + + + + + + Done + + + + diff --git a/web/projects/ui/src/app/modals/enum-list/enum-list.page.scss b/web/projects/ui/src/app/modals/enum-list/enum-list.page.scss new file mode 100644 index 000000000..e69de29bb diff --git a/web/projects/ui/src/app/modals/enum-list/enum-list.page.ts b/web/projects/ui/src/app/modals/enum-list/enum-list.page.ts new file mode 100644 index 000000000..e5ddc8ed3 --- /dev/null +++ b/web/projects/ui/src/app/modals/enum-list/enum-list.page.ts @@ -0,0 +1,50 @@ +import { Component, Input } from '@angular/core' +import { ModalController } from '@ionic/angular' +import { ValueSpecListOf } from 'src/app/pkg-config/config-types' + +@Component({ + selector: 'enum-list', + templateUrl: './enum-list.page.html', + styleUrls: ['./enum-list.page.scss'], +}) +export class EnumListPage { + @Input() key!: string + @Input() spec!: ValueSpecListOf<'enum'> + @Input() current: string[] = [] + + options: { [option: string]: boolean } = {} + selectAll = false + + constructor(private readonly modalCtrl: ModalController) {} + + ngOnInit() { + for (let val of this.spec.spec.values || []) { + this.options[val] = this.current.includes(val) + } + // if none are selected, set selectAll to true + this.selectAll = Object.values(this.options).some(k => !k) + } + + dismiss() { + this.modalCtrl.dismiss() + } + + save() { + this.modalCtrl.dismiss( + Object.keys(this.options).filter(key => this.options[key]), + ) + } + + toggleSelectAll() { + Object.keys(this.options).forEach(k => (this.options[k] = this.selectAll)) + this.selectAll = !this.selectAll + } + + toggleSelected(key: string) { + this.options[key] = !this.options[key] + } + + asIsOrder() { + return 0 + } +} diff --git a/web/projects/ui/src/app/modals/generic-form/generic-form.module.ts b/web/projects/ui/src/app/modals/generic-form/generic-form.module.ts new file mode 100644 index 000000000..f278f652b --- /dev/null +++ b/web/projects/ui/src/app/modals/generic-form/generic-form.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' +import { GenericFormPage } from './generic-form.page' +import { FormsModule, ReactiveFormsModule } from '@angular/forms' +import { FormObjectComponentModule } from 'src/app/components/form-object/form-object.component.module' + +@NgModule({ + declarations: [GenericFormPage], + imports: [ + CommonModule, + IonicModule, + FormsModule, + ReactiveFormsModule, + FormObjectComponentModule, + ], + exports: [GenericFormPage], +}) +export class GenericFormPageModule {} diff --git a/web/projects/ui/src/app/modals/generic-form/generic-form.page.html b/web/projects/ui/src/app/modals/generic-form/generic-form.page.html new file mode 100644 index 000000000..706c8487d --- /dev/null +++ b/web/projects/ui/src/app/modals/generic-form/generic-form.page.html @@ -0,0 +1,35 @@ + + + {{ title }} + + + + + + + + + +
+ + +
+
+ + + + + + {{ button.text }} + + + + diff --git a/web/projects/ui/src/app/modals/generic-form/generic-form.page.scss b/web/projects/ui/src/app/modals/generic-form/generic-form.page.scss new file mode 100644 index 000000000..0353411b3 --- /dev/null +++ b/web/projects/ui/src/app/modals/generic-form/generic-form.page.scss @@ -0,0 +1,9 @@ +button:disabled, +button[disabled]{ + border: 1px solid #999999; + background-color: #cccccc; + color: #666666; +} +button { + color: var(--ion-color-primary); +} \ No newline at end of file diff --git a/web/projects/ui/src/app/modals/generic-form/generic-form.page.ts b/web/projects/ui/src/app/modals/generic-form/generic-form.page.ts new file mode 100644 index 000000000..eb690a787 --- /dev/null +++ b/web/projects/ui/src/app/modals/generic-form/generic-form.page.ts @@ -0,0 +1,61 @@ +import { Component, Input } from '@angular/core' +import { UntypedFormGroup } from '@angular/forms' +import { ModalController } from '@ionic/angular' +import { + convertValuesRecursive, + FormService, +} from 'src/app/services/form.service' +import { ConfigSpec } from 'src/app/pkg-config/config-types' + +export interface ActionButton { + text: string + handler: (value: any) => Promise + isSubmit?: boolean +} + +@Component({ + selector: 'generic-form', + templateUrl: './generic-form.page.html', + styleUrls: ['./generic-form.page.scss'], +}) +export class GenericFormPage { + @Input() title!: string + @Input() spec!: ConfigSpec + @Input() buttons!: ActionButton[] + @Input() initialValue: object = {} + + submitBtn!: ActionButton + formGroup!: UntypedFormGroup + + constructor( + private readonly modalCtrl: ModalController, + private readonly formService: FormService, + ) {} + + ngOnInit() { + this.formGroup = this.formService.createForm(this.spec, this.initialValue) + this.submitBtn = this.buttons.find(btn => btn.isSubmit) || { + text: '', + handler: () => Promise.resolve(true), + } + } + + async dismiss(): Promise { + this.modalCtrl.dismiss() + } + + async handleClick(handler: ActionButton['handler']): Promise { + convertValuesRecursive(this.spec, this.formGroup) + + if (this.formGroup.invalid) { + document + .getElementsByClassName('validation-error')[0] + ?.scrollIntoView({ behavior: 'smooth' }) + return + } + + // @TODO make this more like generic input component dismissal + const success = await handler(this.formGroup.value) + if (success !== false) this.modalCtrl.dismiss() + } +} diff --git a/web/projects/ui/src/app/modals/generic-input/generic-input.component.html b/web/projects/ui/src/app/modals/generic-input/generic-input.component.html new file mode 100644 index 000000000..308afd7dc --- /dev/null +++ b/web/projects/ui/src/app/modals/generic-input/generic-input.component.html @@ -0,0 +1,67 @@ + +
+ + +

{{ options.title }}

+
+

{{ options.message }}

+ +
+

+ {{ options.warning }} +

+
+
+
+ +
+
+

{{ options.label }}

+ + + + + + + +

+ {{ error }} +

+
+ +
+ Cancel + + {{ options.buttonText }} + +
+
+
+
diff --git a/web/projects/ui/src/app/modals/generic-input/generic-input.component.module.ts b/web/projects/ui/src/app/modals/generic-input/generic-input.component.module.ts new file mode 100644 index 000000000..d2b1faab4 --- /dev/null +++ b/web/projects/ui/src/app/modals/generic-input/generic-input.component.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { GenericInputComponent } from './generic-input.component' +import { IonicModule } from '@ionic/angular' +import { RouterModule } from '@angular/router' +import { SharedPipesModule } from '@start9labs/shared' +import { FormsModule } from '@angular/forms' + +@NgModule({ + declarations: [GenericInputComponent], + imports: [ + CommonModule, + IonicModule, + FormsModule, + RouterModule.forChild([]), + SharedPipesModule, + ], + exports: [GenericInputComponent], +}) +export class GenericInputComponentModule {} diff --git a/web/projects/ui/src/app/modals/generic-input/generic-input.component.scss b/web/projects/ui/src/app/modals/generic-input/generic-input.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/web/projects/ui/src/app/modals/generic-input/generic-input.component.ts b/web/projects/ui/src/app/modals/generic-input/generic-input.component.ts new file mode 100644 index 000000000..2ebf80539 --- /dev/null +++ b/web/projects/ui/src/app/modals/generic-input/generic-input.component.ts @@ -0,0 +1,90 @@ +import { Component, inject, Input, ViewChild } from '@angular/core' +import { ModalController, IonicSafeString, IonInput } from '@ionic/angular' +import { getErrorMessage, THEME } from '@start9labs/shared' +import { mask } from 'src/app/util/mask' + +@Component({ + selector: 'generic-input', + templateUrl: './generic-input.component.html', +}) +export class GenericInputComponent { + @ViewChild('mainInput') elem?: IonInput + + @Input() options!: GenericInputOptions + + value!: string + masked!: boolean + + maskedValue?: string + + error: string | IonicSafeString = '' + + readonly theme$ = inject(THEME) + + constructor(private readonly modalCtrl: ModalController) {} + + ngOnInit() { + const defaultOptions: Partial = { + buttonText: 'Submit', + required: true, + useMask: false, + initialValue: '', + } + this.options = { + ...defaultOptions, + ...this.options, + } + + this.masked = !!this.options.useMask + this.value = this.options.initialValue || '' + } + + ngAfterViewInit() { + setTimeout(() => this.elem?.setFocus(), 400) + } + + toggleMask() { + this.masked = !this.masked + } + + cancel() { + this.modalCtrl.dismiss() + } + + transformInput(newValue: string) { + let i = 0 + this.value = newValue + .split('') + .map(x => (x === '●' ? this.value[i++] : x)) + .join('') + this.maskedValue = mask(this.value) + } + + async submit() { + const value = this.value.trim() + + if (!value && this.options.required) return + + try { + const response = await this.options.submitFn(value) + this.modalCtrl.dismiss({ response, value }, 'success') + } catch (e: any) { + this.error = getErrorMessage(e) + } + } +} + +export interface GenericInputOptions { + // required + title: string + message: string + submitFn: (value: string) => Promise + // optional + label?: string + warning?: string + buttonText?: string + placeholder?: string + required?: boolean + useMask?: boolean + initialValue?: string | null +} diff --git a/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.module.ts b/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.module.ts new file mode 100644 index 000000000..9eaebbd34 --- /dev/null +++ b/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.module.ts @@ -0,0 +1,27 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' +import { SharedPipesModule } from '@start9labs/shared' +import { + TuiDataListModule, + TuiHostedDropdownModule, + TuiSvgModule, +} from '@taiga-ui/core' +import { StoreIconComponentModule } from 'src/app/common/store-icon/store-icon.component.module' +import { FormPageModule } from 'src/app/apps/ui/modals/form/form.module' +import { MarketplaceSettingsPage } from './marketplace-settings.page' + +@NgModule({ + imports: [ + CommonModule, + IonicModule, + SharedPipesModule, + StoreIconComponentModule, + TuiHostedDropdownModule, + TuiDataListModule, + TuiSvgModule, + FormPageModule, + ], + declarations: [MarketplaceSettingsPage], +}) +export class MarketplaceSettingsPageModule {} diff --git a/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.html b/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.html new file mode 100644 index 000000000..663b022cd --- /dev/null +++ b/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.html @@ -0,0 +1,67 @@ + + + Change Registry + + + + + + + + + + + Default Registries + + + + + +

{{ s.name }}

+

{{ s.url }}

+
+ +
+ + Custom Registries + + + + + Add custom registry + + + + + + + +

{{ a.name }}

+

{{ a.url }}

+
+ +
+
+
diff --git a/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.scss b/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.scss new file mode 100644 index 000000000..e69de29bb diff --git a/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.ts b/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.ts new file mode 100644 index 000000000..09d30780e --- /dev/null +++ b/web/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.ts @@ -0,0 +1,230 @@ +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core' +import { ErrorService, sameUrl, toUrl } from '@start9labs/shared' +import { AbstractMarketplaceService } from '@start9labs/marketplace' +import { ValueSpecObject } from '@start9labs/start-sdk/lib/config/configTypes' +import { TuiDialogService } from '@taiga-ui/core' +import { TUI_PROMPT } from '@taiga-ui/kit' +import { PatchDB } from 'patch-db-client' +import { combineLatest, filter, firstValueFrom, map, Subscription } from 'rxjs' +import { ApiService } from 'src/app/services/api/embassy-api.service' +import { DataModel, UIStore } from 'src/app/services/patch-db/data-model' +import { MarketplaceService } from 'src/app/services/marketplace.service' +import { FormDialogService } from 'src/app/services/form-dialog.service' +import { FormPage } from 'src/app/apps/ui/modals/form/form.page' +import { LoadingService } from 'src/app/common/loading/loading.service' + +@Component({ + selector: 'marketplace-settings', + templateUrl: 'marketplace-settings.page.html', + styleUrls: ['marketplace-settings.page.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MarketplaceSettingsPage { + stores$ = combineLatest([ + this.marketplaceService.getKnownHosts$(), + this.marketplaceService.getSelectedHost$(), + ]).pipe( + map(([stores, selected]) => { + const toSlice = stores.map(s => ({ + ...s, + selected: sameUrl(s.url, selected.url), + })) + // 0 and 1 are prod and community + const standard = toSlice.slice(0, 2) + // 2 and beyond are alts + const alt = toSlice.slice(2) + + return { standard, alt } + }), + ) + + constructor( + private readonly api: ApiService, + private readonly loader: LoadingService, + private readonly formDialog: FormDialogService, + private readonly errorService: ErrorService, + @Inject(AbstractMarketplaceService) + private readonly marketplaceService: MarketplaceService, + private readonly patch: PatchDB, + private readonly dialogs: TuiDialogService, + ) {} + + async presentModalAdd() { + const { name, spec } = getMarketplaceValueSpec() + + this.formDialog.open(FormPage, { + label: name, + data: { + spec, + buttons: [ + { + text: 'Save for Later', + handler: async (value: { url: string }) => this.saveOnly(value.url), + }, + { + text: 'Save and Connect', + handler: async (value: { url: string }) => + this.saveAndConnect(value.url), + isSubmit: true, + }, + ], + }, + }) + } + + async presentAlertDelete(url: string, name: string = '') { + this.dialogs + .open(TUI_PROMPT, { + label: 'Confirm', + size: 's', + data: { + content: `Are you sure you want to delete ${name}?`, + yes: 'Delete', + no: 'Cancel', + }, + }) + .pipe(filter(Boolean)) + .subscribe(() => this.delete(url)) + } + + async connect( + url: string, + loader: Subscription = new Subscription(), + ): Promise { + loader.unsubscribe() + loader.closed = false + loader.add(this.loader.open('Changing Registry...').subscribe()) + + try { + await this.api.setDbValue(['marketplace', 'selected-url'], url) + } catch (e: any) { + this.errorService.handleError(e) + } finally { + loader.unsubscribe() + } + } + + private async saveOnly(rawUrl: string): Promise { + const loader = this.loader.open('Loading').subscribe() + + try { + const url = new URL(rawUrl).toString() + await this.validateAndSave(url, loader) + return true + } catch (e: any) { + this.errorService.handleError(e) + return false + } finally { + loader.unsubscribe() + } + } + + private async saveAndConnect(rawUrl: string): Promise { + const loader = this.loader.open('Loading').subscribe() + + try { + const url = new URL(rawUrl).toString() + await this.validateAndSave(url, loader) + await this.connect(url, loader) + return true + } catch (e: any) { + this.errorService.handleError(e) + return false + } finally { + loader.unsubscribe() + } + } + + private async validateAndSave( + url: string, + loader: Subscription, + ): Promise { + // Error on duplicates + const hosts = await firstValueFrom( + this.patch.watch$('ui', 'marketplace', 'known-hosts'), + ) + const currentUrls = Object.keys(hosts).map(toUrl) + if (currentUrls.includes(url)) throw new Error('marketplace already added') + + // Validate + loader.unsubscribe() + loader.closed = false + loader.add(this.loader.open('Validating marketplace...').subscribe()) + + const { name } = await firstValueFrom( + this.marketplaceService.fetchInfo$(url), + ) + + // Save + loader.unsubscribe() + loader.closed = false + loader.add(this.loader.open('Saving...').subscribe()) + + await this.api.setDbValue<{ name: string }>( + ['marketplace', 'known-hosts', url], + { name }, + ) + } + + private async delete(url: string): Promise { + const loader = this.loader.open('Deleting...').subscribe() + + const hosts = await firstValueFrom( + this.patch.watch$('ui', 'marketplace', 'known-hosts'), + ) + + const filtered: { [url: string]: UIStore } = Object.keys(hosts) + .filter(key => !sameUrl(key, url)) + .reduce((prev, curr) => { + const name = hosts[curr] + return { + ...prev, + [curr]: name, + } + }, {}) + + try { + await this.api.setDbValue<{ [url: string]: UIStore }>( + ['marketplace', 'known-hosts'], + filtered, + ) + } catch (e: any) { + this.errorService.handleError(e) + } finally { + loader.unsubscribe() + } + } +} + +function getMarketplaceValueSpec(): ValueSpecObject { + return { + type: 'object', + name: 'Add Custom Registry', + description: null, + warning: null, + spec: { + url: { + type: 'text', + name: 'URL', + description: 'A fully-qualified URL of the custom registry', + inputmode: 'url', + required: true, + masked: false, + minLength: null, + maxLength: null, + patterns: [ + { + regex: `https?:\/\/[a-zA-Z0-9][a-zA-Z0-9-\.]+[a-zA-Z0-9]\.[^\s]{2,}`, + description: 'Must be a valid URL', + }, + ], + placeholder: 'e.g. https://example.org', + default: null, + warning: null, + disabled: false, + immutable: false, + generate: null, + }, + }, + } +} diff --git a/web/projects/ui/src/app/modals/os-update/os-update.page.html b/web/projects/ui/src/app/modals/os-update/os-update.page.html new file mode 100644 index 000000000..011a5cc51 --- /dev/null +++ b/web/projects/ui/src/app/modals/os-update/os-update.page.html @@ -0,0 +1,43 @@ + + +
+ + StartOS {{ versions[0].version }} + +
+ + Release Notes + +
+ + + + + +
+
+ + +
+ +

{{ v.version }}

+
+
+
+
+
+ + + + + + Begin Update + + + + diff --git a/web/projects/ui/src/app/modals/os-update/os-update.page.module.ts b/web/projects/ui/src/app/modals/os-update/os-update.page.module.ts new file mode 100644 index 000000000..2d3e0176a --- /dev/null +++ b/web/projects/ui/src/app/modals/os-update/os-update.page.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' +import { OSUpdatePage } from './os-update.page' +import { MarkdownPipeModule } from '@start9labs/shared' + +@NgModule({ + declarations: [OSUpdatePage], + imports: [CommonModule, IonicModule, MarkdownPipeModule], + exports: [OSUpdatePage], +}) +export class OSUpdatePageModule {} diff --git a/web/projects/ui/src/app/modals/os-update/os-update.page.scss b/web/projects/ui/src/app/modals/os-update/os-update.page.scss new file mode 100644 index 000000000..586a54126 --- /dev/null +++ b/web/projects/ui/src/app/modals/os-update/os-update.page.scss @@ -0,0 +1,6 @@ +.underline { + margin: 6px 0 8px 16px; + border-style: solid; + border-width: 0px 0px 1px 0px; + border-color: #404040; + } \ No newline at end of file diff --git a/web/projects/ui/src/app/modals/os-update/os-update.page.ts b/web/projects/ui/src/app/modals/os-update/os-update.page.ts new file mode 100644 index 000000000..ffc544459 --- /dev/null +++ b/web/projects/ui/src/app/modals/os-update/os-update.page.ts @@ -0,0 +1,61 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { LoadingController, ModalController } from '@ionic/angular' +import { ErrorToastService } from '@start9labs/shared' +import { ApiService } from 'src/app/services/api/embassy-api.service' +import { EOSService } from 'src/app/services/eos.service' + +@Component({ + selector: 'os-update', + templateUrl: './os-update.page.html', + styleUrls: ['./os-update.page.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class OSUpdatePage { + versions: { version: string; notes: string }[] = [] + + constructor( + private readonly modalCtrl: ModalController, + private readonly loadingCtrl: LoadingController, + private readonly errToast: ErrorToastService, + private readonly embassyApi: ApiService, + private readonly eosService: EOSService, + ) {} + + ngOnInit() { + const releaseNotes = this.eosService.eos?.['release-notes']! + + this.versions = Object.keys(releaseNotes) + .sort() + .reverse() + .map(version => { + return { + version, + notes: releaseNotes[version], + } + }) + } + + dismiss() { + this.modalCtrl.dismiss() + } + + async updateEOS() { + const loader = await this.loadingCtrl.create({ + message: 'Beginning update...', + }) + await loader.present() + + try { + await this.embassyApi.updateServer() + this.dismiss() + } catch (e: any) { + this.errToast.present(e) + } finally { + loader.dismiss() + } + } + + asIsOrder() { + return 0 + } +} diff --git a/web/projects/ui/src/app/modals/os-welcome/os-welcome.module.ts b/web/projects/ui/src/app/modals/os-welcome/os-welcome.module.ts new file mode 100644 index 000000000..cabce3502 --- /dev/null +++ b/web/projects/ui/src/app/modals/os-welcome/os-welcome.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' +import { SharedPipesModule } from '@start9labs/shared' +import { FormsModule } from '@angular/forms' +import { OSWelcomePage } from './os-welcome.page' + +@NgModule({ + declarations: [OSWelcomePage], + imports: [CommonModule, IonicModule, FormsModule, SharedPipesModule], + exports: [OSWelcomePage], +}) +export class OSWelcomePageModule {} diff --git a/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.html b/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.html new file mode 100644 index 000000000..ed05ccb45 --- /dev/null +++ b/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.html @@ -0,0 +1,53 @@ + + + Release Notes + + + + + + + + + +

This Release

+ +

0.3.5

+

+ View the complete + + release notes + + for more details. +

+
Highlights
+
    +
  • + This release contains significant under-the-hood improvements to + performance and reliability +
  • +
  • Ditch Docker, replace with Podman
  • +
  • Remove locking behavior from PatchDB and optimize
  • +
  • Boost efficiency of service manager
  • +
  • Require HTTPS on LAN, and improve setup flow for trusting Root CA
  • +
  • Better default privacy settings for Firefox kiosk mode
  • +
  • Eliminate memory leak from Javascript runtime
  • +
  • Other small bug fixes
  • +
  • Update license to MIT
  • +
+ +
+ + Begin + +
+
diff --git a/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.scss b/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.scss new file mode 100644 index 000000000..0dc939f99 --- /dev/null +++ b/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.scss @@ -0,0 +1,29 @@ +.close-button { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + min-height: 100px; +} + +.main-content { + color: var(--ion-color-dark); +} + +.spaced-list { + li { + padding-bottom: 12px; + } +} + +.note-padding { + padding-bottom: 12px; +} + +h2 { + font-weight: bold; +} + +h4 { + font-style: italic; +} \ No newline at end of file diff --git a/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.ts b/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.ts new file mode 100644 index 000000000..f9a6ecd7b --- /dev/null +++ b/web/projects/ui/src/app/modals/os-welcome/os-welcome.page.ts @@ -0,0 +1,15 @@ +import { Component, Input } from '@angular/core' +import { ModalController } from '@ionic/angular' + +@Component({ + selector: 'os-welcome', + templateUrl: './os-welcome.page.html', + styleUrls: ['./os-welcome.page.scss'], +}) +export class OSWelcomePage { + constructor(private readonly modalCtrl: ModalController) {} + + async dismiss() { + return this.modalCtrl.dismiss() + } +} diff --git a/web/projects/ui/src/app/modals/snake/snake.module.ts b/web/projects/ui/src/app/modals/snake/snake.module.ts new file mode 100644 index 000000000..cc9c937d0 --- /dev/null +++ b/web/projects/ui/src/app/modals/snake/snake.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { IonicModule } from '@ionic/angular' + +import { SnakePage } from './snake.page' + +@NgModule({ + imports: [CommonModule, IonicModule], + declarations: [SnakePage], + exports: [SnakePage], +}) +export class SnakePageModule {} diff --git a/web/projects/ui/src/app/modals/snake/snake.page.html b/web/projects/ui/src/app/modals/snake/snake.page.html new file mode 100644 index 000000000..9e037ce8d --- /dev/null +++ b/web/projects/ui/src/app/modals/snake/snake.page.html @@ -0,0 +1,28 @@ + + + Play Snek! + Score: {{ score }} + + + + +
+ +
+
+ + + + High Score: {{ highScore }} + + + Save and Quit + + + + diff --git a/web/projects/ui/src/app/modals/snake/snake.page.scss b/web/projects/ui/src/app/modals/snake/snake.page.scss new file mode 100644 index 000000000..c07d3a2b7 --- /dev/null +++ b/web/projects/ui/src/app/modals/snake/snake.page.scss @@ -0,0 +1,6 @@ +.canvas-center { + padding-top: 20px; + display: flex; + align-items: center; + justify-content: center; +} \ No newline at end of file diff --git a/web/projects/ui/src/app/modals/snake/snake.page.ts b/web/projects/ui/src/app/modals/snake/snake.page.ts new file mode 100644 index 000000000..6c671201d --- /dev/null +++ b/web/projects/ui/src/app/modals/snake/snake.page.ts @@ -0,0 +1,255 @@ +import { Component, HostListener, Input } from '@angular/core' +import { ModalController } from '@ionic/angular' +import { pauseFor } from '../../../../../shared/src/public-api' + +@Component({ + selector: 'snake', + templateUrl: './snake.page.html', + styleUrls: ['./snake.page.scss'], +}) +export class SnakePage { + @Input() + highScore = 0 + + score = 0 + + private readonly speed = 45 + private readonly width = 40 + private readonly height = 26 + private grid = NaN + + private readonly startingLength = 4 + + private xDown?: number + private yDown?: number + private canvas!: HTMLCanvasElement + private image!: HTMLImageElement + private context!: CanvasRenderingContext2D + + private snake: any + private bitcoin: { x: number; y: number } = { x: NaN, y: NaN } + + private moveQueue: String[] = [] + + constructor(private readonly modalCtrl: ModalController) {} + + async dismiss() { + return this.modalCtrl.dismiss({ highScore: this.highScore }) + } + + @HostListener('document:keydown', ['$event']) + keyEvent(e: KeyboardEvent) { + this.moveQueue.push(e.key) + } + + @HostListener('touchstart', ['$event']) + touchStart(e: TouchEvent) { + this.handleTouchStart(e) + } + + @HostListener('touchmove', ['$event']) + touchMove(e: TouchEvent) { + this.handleTouchMove(e) + } + + @HostListener('window:resize') + sizeChange() { + this.init() + } + + ionViewDidEnter() { + this.init() + + this.image = new Image() + this.image.onload = () => { + requestAnimationFrame(async () => await this.loop()) + } + this.image.src = '../../../../../../assets/img/icons/bitcoin.svg' + } + + init() { + this.canvas = document.querySelector('canvas#game')! + this.canvas.style.border = '1px solid #e0e0e0' + this.context = this.canvas.getContext('2d')! + const container = document.getElementsByClassName('canvas-center')[0] + this.grid = Math.min( + Math.floor(container.clientWidth / this.width), + Math.floor(container.clientHeight / this.height), + ) + this.snake = { + x: this.grid * (Math.floor(this.width / 2) - this.startingLength), + y: this.grid * Math.floor(this.height / 2), + // snake velocity. moves one grid length every frame in either the x or y direction + dx: this.grid, + dy: 0, + // keep track of all grids the snake body occupies + cells: [], + // length of the snake. grows when eating an bitcoin + maxCells: this.startingLength, + } + this.bitcoin = { + x: this.getRandomInt(0, this.width) * this.grid, + y: this.getRandomInt(0, this.height) * this.grid, + } + + this.canvas.width = this.grid * this.width + this.canvas.height = this.grid * this.height + this.context.imageSmoothingEnabled = false + } + + getTouches(evt: TouchEvent) { + return evt.touches + } + + handleTouchStart(evt: TouchEvent) { + const firstTouch = this.getTouches(evt)[0] + this.xDown = firstTouch.clientX + this.yDown = firstTouch.clientY + } + + handleTouchMove(evt: TouchEvent) { + if (!this.xDown || !this.yDown) { + return + } + + var xUp = evt.touches[0].clientX + var yUp = evt.touches[0].clientY + + var xDiff = this.xDown - xUp + var yDiff = this.yDown - yUp + + if (Math.abs(xDiff) > Math.abs(yDiff)) { + /*most significant*/ + if (xDiff > 0) { + this.moveQueue.push('ArrowLeft') + } else { + this.moveQueue.push('ArrowRight') + } + } else { + if (yDiff > 0) { + this.moveQueue.push('ArrowUp') + } else { + this.moveQueue.push('ArrowDown') + } + } + /* reset values */ + this.xDown = undefined + this.yDown = undefined + } + + // game loop + async loop() { + await pauseFor(this.speed) + + requestAnimationFrame(async () => await this.loop()) + + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height) + + // move snake by it's velocity + this.snake.x += this.snake.dx + this.snake.y += this.snake.dy + + if (this.moveQueue.length) { + const move = this.moveQueue.shift() + // left arrow key + if (move === 'ArrowLeft' && this.snake.dx === 0) { + this.snake.dx = -this.grid + this.snake.dy = 0 + } + // up arrow key + else if (move === 'ArrowUp' && this.snake.dy === 0) { + this.snake.dy = -this.grid + this.snake.dx = 0 + } + // right arrow key + else if (move === 'ArrowRight' && this.snake.dx === 0) { + this.snake.dx = this.grid + this.snake.dy = 0 + } + // down arrow key + else if (move === 'ArrowDown' && this.snake.dy === 0) { + this.snake.dy = this.grid + this.snake.dx = 0 + } + } + + // edge death + if ( + this.snake.x < 0 || + this.snake.y < 0 || + this.snake.x >= this.canvas.width || + this.snake.y >= this.canvas.height + ) { + this.death() + } + + // keep track of where snake has been. front of the array is always the head + this.snake.cells.unshift({ x: this.snake.x, y: this.snake.y }) + + // remove cells as we move away from them + if (this.snake.cells.length > this.snake.maxCells) { + this.snake.cells.pop() + } + + // draw bitcoin + this.context.fillStyle = '#ff4961' + this.context.drawImage( + this.image, + this.bitcoin.x - 1, + this.bitcoin.y - 1, + this.grid + 2, + this.grid + 2, + ) + + // draw snake one cell at a time + this.context.fillStyle = '#2fdf75' + + const firstCell = this.snake.cells[0] + + for (let index = 0; index < this.snake.cells.length; index++) { + const cell = this.snake.cells[index] + + // drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is + this.context.fillRect(cell.x, cell.y, this.grid - 1, this.grid - 1) + + // snake ate bitcoin + if (cell.x === this.bitcoin.x && cell.y === this.bitcoin.y) { + this.score++ + this.highScore = Math.max(this.score, this.highScore) + this.snake.maxCells++ + + this.bitcoin.x = this.getRandomInt(0, this.width) * this.grid + this.bitcoin.y = this.getRandomInt(0, this.height) * this.grid + } + + if (index > 0) { + // check collision with all cells after this one (modified bubble sort) + // snake occupies same space as a body part. reset game + if ( + firstCell.x === this.snake.cells[index].x && + firstCell.y === this.snake.cells[index].y + ) { + this.death() + } + } + } + } + + death() { + this.snake.x = + this.grid * (Math.floor(this.width / 2) - this.startingLength) + this.snake.y = this.grid * Math.floor(this.height / 2) + this.snake.cells = [] + this.snake.maxCells = this.startingLength + this.snake.dx = this.grid + this.snake.dy = 0 + + this.bitcoin.x = this.getRandomInt(0, 25) * this.grid + this.bitcoin.y = this.getRandomInt(0, 25) * this.grid + this.score = 0 + } + + getRandomInt(min: number, max: number) { + return Math.floor(Math.random() * (max - min)) + min + } +} diff --git a/web/projects/ui/src/app/pipes/backup-color/backup-color.module.ts b/web/projects/ui/src/app/pipes/backup-color/backup-color.module.ts new file mode 100644 index 000000000..3451791e1 --- /dev/null +++ b/web/projects/ui/src/app/pipes/backup-color/backup-color.module.ts @@ -0,0 +1,8 @@ +import { NgModule } from '@angular/core' +import { BackupColorPipe } from './backup-color.pipe' + +@NgModule({ + declarations: [BackupColorPipe], + exports: [BackupColorPipe], +}) +export class BackupColorPipeModule {} diff --git a/web/projects/ui/src/app/pipes/backup-color/backup-color.pipe.ts b/web/projects/ui/src/app/pipes/backup-color/backup-color.pipe.ts new file mode 100644 index 000000000..461afa03e --- /dev/null +++ b/web/projects/ui/src/app/pipes/backup-color/backup-color.pipe.ts @@ -0,0 +1,23 @@ +import { Pipe, PipeTransform } from '@angular/core' + +@Pipe({ + name: 'backupColor', +}) +export class BackupColorPipe implements PipeTransform { + transform(lastBackup: string | null): 'success' | 'warning' | 'danger' { + if (!lastBackup) return 'danger' + + const currentDate = new Date().valueOf() + const backupDate = new Date(lastBackup).valueOf() + const diff = currentDate - backupDate + const week = 604800000 + + if (diff <= week) { + return 'success' + } else if (diff > week && diff <= week * 2) { + return 'warning' + } else { + return 'danger' + } + } +} diff --git a/web/projects/ui/src/app/pipes/install-progress/install-progress.module.ts b/web/projects/ui/src/app/pipes/install-progress/install-progress.module.ts new file mode 100644 index 000000000..37bbd0744 --- /dev/null +++ b/web/projects/ui/src/app/pipes/install-progress/install-progress.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core' +import { + InstallProgressDisplayPipe, + InstallProgressPipe, +} from './install-progress.pipe' + +@NgModule({ + declarations: [InstallProgressPipe, InstallProgressDisplayPipe], + exports: [InstallProgressPipe, InstallProgressDisplayPipe], +}) +export class InstallProgressPipeModule {} diff --git a/web/projects/ui/src/app/pipes/install-progress/install-progress.pipe.ts b/web/projects/ui/src/app/pipes/install-progress/install-progress.pipe.ts new file mode 100644 index 000000000..9ecf86dc3 --- /dev/null +++ b/web/projects/ui/src/app/pipes/install-progress/install-progress.pipe.ts @@ -0,0 +1,12 @@ +import { Pipe, PipeTransform } from '@angular/core' +import { InstallProgress } from 'src/app/services/patch-db/data-model' +import { packageLoadingProgress } from 'src/app/util/package-loading-progress' + +@Pipe({ + name: 'installProgress', +}) +export class InstallProgressPipe implements PipeTransform { + transform(installProgress?: InstallProgress): number { + return packageLoadingProgress(installProgress)?.totalProgress || 0 + } +} diff --git a/web/projects/ui/src/app/pipes/launchable/launchable.module.ts b/web/projects/ui/src/app/pipes/launchable/launchable.module.ts new file mode 100644 index 000000000..9d516789f --- /dev/null +++ b/web/projects/ui/src/app/pipes/launchable/launchable.module.ts @@ -0,0 +1,8 @@ +import { NgModule } from '@angular/core' +import { LaunchablePipe } from './launchable.pipe' + +@NgModule({ + declarations: [LaunchablePipe], + exports: [LaunchablePipe], +}) +export class LaunchablePipeModule {} diff --git a/web/projects/ui/src/app/pipes/launchable/launchable.pipe.ts b/web/projects/ui/src/app/pipes/launchable/launchable.pipe.ts new file mode 100644 index 000000000..be1d5218d --- /dev/null +++ b/web/projects/ui/src/app/pipes/launchable/launchable.pipe.ts @@ -0,0 +1,22 @@ +import { Pipe, PipeTransform } from '@angular/core' +import { + InterfaceDef, + PackageMainStatus, + PackageState, +} from 'src/app/services/patch-db/data-model' +import { ConfigService } from '../../services/config.service' + +@Pipe({ + name: 'isLaunchable', +}) +export class LaunchablePipe implements PipeTransform { + constructor(private configService: ConfigService) {} + + transform( + state: PackageState, + status: PackageMainStatus, + interfaces: Record, + ): boolean { + return this.configService.isLaunchable(state, status, interfaces) + } +} diff --git a/web/projects/ui/src/app/pipes/mask/mask.module.ts b/web/projects/ui/src/app/pipes/mask/mask.module.ts new file mode 100644 index 000000000..13950e553 --- /dev/null +++ b/web/projects/ui/src/app/pipes/mask/mask.module.ts @@ -0,0 +1,8 @@ +import { NgModule } from '@angular/core' +import { MaskPipe } from './mask.pipe' + +@NgModule({ + declarations: [MaskPipe], + exports: [MaskPipe], +}) +export class MaskPipeModule {} diff --git a/web/projects/ui/src/app/pipes/mask/mask.pipe.ts b/web/projects/ui/src/app/pipes/mask/mask.pipe.ts new file mode 100644 index 000000000..140f4b303 --- /dev/null +++ b/web/projects/ui/src/app/pipes/mask/mask.pipe.ts @@ -0,0 +1,11 @@ +import { Pipe, PipeTransform } from '@angular/core' + +@Pipe({ + name: 'mask', +}) +export class MaskPipe implements PipeTransform { + transform(val: string, max?: number): string { + const length = max ? Math.min(max, val.length) : val.length + return '●'.repeat(length) + } +} diff --git a/web/projects/ui/src/app/pipes/ui/ui.module.ts b/web/projects/ui/src/app/pipes/ui/ui.module.ts new file mode 100644 index 000000000..9637306de --- /dev/null +++ b/web/projects/ui/src/app/pipes/ui/ui.module.ts @@ -0,0 +1,8 @@ +import { NgModule } from '@angular/core' +import { UiPipe } from './ui.pipe' + +@NgModule({ + declarations: [UiPipe], + exports: [UiPipe], +}) +export class UiPipeModule {} diff --git a/web/projects/ui/src/app/pipes/ui/ui.pipe.ts b/web/projects/ui/src/app/pipes/ui/ui.pipe.ts new file mode 100644 index 000000000..9d46bfd86 --- /dev/null +++ b/web/projects/ui/src/app/pipes/ui/ui.pipe.ts @@ -0,0 +1,12 @@ +import { Pipe, PipeTransform } from '@angular/core' +import { InterfaceDef } from '../../services/patch-db/data-model' +import { hasUi } from '../../services/config.service' + +@Pipe({ + name: 'hasUi', +}) +export class UiPipe implements PipeTransform { + transform(interfaces: Record): boolean { + return hasUi(interfaces) + } +} diff --git a/web/projects/ui/src/app/pkg-config/config-types.ts b/web/projects/ui/src/app/pkg-config/config-types.ts new file mode 100644 index 000000000..08f0b9d26 --- /dev/null +++ b/web/projects/ui/src/app/pkg-config/config-types.ts @@ -0,0 +1,171 @@ +export type ConfigSpec = Record + +export type ValueType = + | 'string' + | 'number' + | 'boolean' + | 'enum' + | 'list' + | 'object' + | 'pointer' + | 'union' +export type ValueSpec = ValueSpecOf + +// core spec types. These types provide the metadata for performing validations +export type ValueSpecOf = T extends 'string' + ? ValueSpecString + : T extends 'number' + ? ValueSpecNumber + : T extends 'boolean' + ? ValueSpecBoolean + : T extends 'enum' + ? ValueSpecEnum + : T extends 'list' + ? ValueSpecList + : T extends 'object' + ? ValueSpecObject + : T extends 'pointer' + ? ValueSpecPointer + : T extends 'union' + ? ValueSpecUnion + : never + +export interface ValueSpecString extends ListValueSpecString, WithStandalone { + type: 'string' + default?: DefaultString + nullable: boolean + textarea?: boolean +} + +export interface ValueSpecNumber extends ListValueSpecNumber, WithStandalone { + type: 'number' + nullable: boolean + default?: number +} + +export interface ValueSpecEnum extends ListValueSpecEnum, WithStandalone { + type: 'enum' + default: string +} + +export interface ValueSpecBoolean extends WithStandalone { + type: 'boolean' + default: boolean +} + +export interface ValueSpecUnion { + type: 'union' + tag: UnionTagSpec + variants: { [key: string]: ConfigSpec } + default: string +} + +export interface ValueSpecPointer extends WithStandalone { + type: 'pointer' + subtype: 'package' | 'system' + 'package-id': string + target: 'lan-address' | 'tor-address' | 'config' | 'tor-key' + interface: string // will only exist if target = tor-key || tor-address || lan-address + selector?: string // will only exist if target = config + multi?: boolean // will only exist if target = config +} + +export interface ValueSpecObject extends WithStandalone { + type: 'object' + spec: ConfigSpec +} + +export interface WithStandalone { + name: string + description?: string + warning?: string +} + +// no lists of booleans, lists, pointers +export type ListValueSpecType = + | 'string' + | 'number' + | 'enum' + | 'object' + | 'union' + +// represents a spec for the values of a list +export type ListValueSpecOf = T extends 'string' + ? ListValueSpecString + : T extends 'number' + ? ListValueSpecNumber + : T extends 'enum' + ? ListValueSpecEnum + : T extends 'object' + ? ListValueSpecObject + : T extends 'union' + ? ListValueSpecUnion + : never + +// represents a spec for a list +export type ValueSpecList = ValueSpecListOf +export interface ValueSpecListOf + extends WithStandalone { + type: 'list' + subtype: T + spec: ListValueSpecOf + range: string // '[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules + default: string[] | number[] | DefaultString[] | object[] +} + +// sometimes the type checker needs just a little bit of help +export function isValueSpecListOf( + t: ValueSpecList, + s: S, +): t is ValueSpecListOf { + return t.subtype === s +} + +export interface ListValueSpecString { + pattern?: string + 'pattern-description'?: string + masked: boolean + copyable: boolean + placeholder?: string +} + +export interface ListValueSpecNumber { + range: string + integral: boolean + units?: string + placeholder?: string +} + +export interface ListValueSpecEnum { + values: string[] + 'value-names': { [value: string]: string } +} + +export interface ListValueSpecObject { + spec: ConfigSpec // this is a mapped type of the config object at this level, replacing the object's values with specs on those values + 'unique-by': UniqueBy // indicates whether duplicates can be permitted in the list + 'display-as'?: string // this should be a handlebars template which can make use of the entire config which corresponds to 'spec' +} + +export type UniqueBy = null | string | { any: UniqueBy[] } | { all: UniqueBy[] } + +export interface ListValueSpecUnion { + tag: UnionTagSpec + variants: { [key: string]: ConfigSpec } + 'display-as'?: string // this may be a handlebars template which can conditionally (on tag.id) make use of each union's entries, or if left blank will display as tag.id + 'unique-by': UniqueBy + default: string // this should be the variantName which one prefers a user to start with by default when creating a new union instance in a list +} + +export interface UnionTagSpec { + id: string // The name of the field containing one of the union variants + 'variant-names': { + // the name of each variant + [variant: string]: string + } + name: string + description?: string + warning?: string +} + +export type DefaultString = string | { charset: string; len: number } diff --git a/frontend/projects/ui/src/app/util/config-utilities.ts b/web/projects/ui/src/app/pkg-config/config-utilities.ts similarity index 100% rename from frontend/projects/ui/src/app/util/config-utilities.ts rename to web/projects/ui/src/app/pkg-config/config-utilities.ts diff --git a/frontend/projects/ui/src/app/routing.module.ts b/web/projects/ui/src/app/routing.module.ts similarity index 100% rename from frontend/projects/ui/src/app/routing.module.ts rename to web/projects/ui/src/app/routing.module.ts diff --git a/frontend/projects/ui/src/app/services/api/api-icons.ts b/web/projects/ui/src/app/services/api/api-icons.ts similarity index 100% rename from frontend/projects/ui/src/app/services/api/api-icons.ts rename to web/projects/ui/src/app/services/api/api-icons.ts diff --git a/frontend/projects/ui/src/app/services/api/api.fixures.ts b/web/projects/ui/src/app/services/api/api.fixures.ts similarity index 100% rename from frontend/projects/ui/src/app/services/api/api.fixures.ts rename to web/projects/ui/src/app/services/api/api.fixures.ts diff --git a/frontend/projects/ui/src/app/services/api/api.types.ts b/web/projects/ui/src/app/services/api/api.types.ts similarity index 100% rename from frontend/projects/ui/src/app/services/api/api.types.ts rename to web/projects/ui/src/app/services/api/api.types.ts diff --git a/frontend/projects/ui/src/app/services/api/embassy-api.service.ts b/web/projects/ui/src/app/services/api/embassy-api.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/api/embassy-api.service.ts rename to web/projects/ui/src/app/services/api/embassy-api.service.ts diff --git a/frontend/projects/ui/src/app/services/api/embassy-live-api.service.ts b/web/projects/ui/src/app/services/api/embassy-live-api.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/api/embassy-live-api.service.ts rename to web/projects/ui/src/app/services/api/embassy-live-api.service.ts diff --git a/frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts b/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/api/embassy-mock-api.service.ts rename to web/projects/ui/src/app/services/api/embassy-mock-api.service.ts diff --git a/frontend/projects/ui/src/app/services/api/mock-patch.ts b/web/projects/ui/src/app/services/api/mock-patch.ts similarity index 100% rename from frontend/projects/ui/src/app/services/api/mock-patch.ts rename to web/projects/ui/src/app/services/api/mock-patch.ts diff --git a/frontend/projects/ui/src/app/services/auth.service.ts b/web/projects/ui/src/app/services/auth.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/auth.service.ts rename to web/projects/ui/src/app/services/auth.service.ts diff --git a/frontend/projects/ui/src/app/services/client-storage.service.ts b/web/projects/ui/src/app/services/client-storage.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/client-storage.service.ts rename to web/projects/ui/src/app/services/client-storage.service.ts diff --git a/frontend/projects/ui/src/app/services/config.service.ts b/web/projects/ui/src/app/services/config.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/config.service.ts rename to web/projects/ui/src/app/services/config.service.ts diff --git a/frontend/projects/ui/src/app/services/connection.service.ts b/web/projects/ui/src/app/services/connection.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/connection.service.ts rename to web/projects/ui/src/app/services/connection.service.ts diff --git a/frontend/projects/ui/src/app/services/date-transformer.service.ts b/web/projects/ui/src/app/services/date-transformer.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/date-transformer.service.ts rename to web/projects/ui/src/app/services/date-transformer.service.ts diff --git a/frontend/projects/ui/src/app/services/datetime-transformer.service.ts b/web/projects/ui/src/app/services/datetime-transformer.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/datetime-transformer.service.ts rename to web/projects/ui/src/app/services/datetime-transformer.service.ts diff --git a/frontend/projects/ui/src/app/services/dep-error.service.ts b/web/projects/ui/src/app/services/dep-error.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/dep-error.service.ts rename to web/projects/ui/src/app/services/dep-error.service.ts diff --git a/frontend/projects/ui/src/app/services/eos.service.ts b/web/projects/ui/src/app/services/eos.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/eos.service.ts rename to web/projects/ui/src/app/services/eos.service.ts diff --git a/frontend/projects/ui/src/app/services/form-dialog.service.ts b/web/projects/ui/src/app/services/form-dialog.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/form-dialog.service.ts rename to web/projects/ui/src/app/services/form-dialog.service.ts diff --git a/frontend/projects/ui/src/app/services/form.service.ts b/web/projects/ui/src/app/services/form.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/form.service.ts rename to web/projects/ui/src/app/services/form.service.ts diff --git a/frontend/projects/ui/src/app/services/marketplace.service.ts b/web/projects/ui/src/app/services/marketplace.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/marketplace.service.ts rename to web/projects/ui/src/app/services/marketplace.service.ts diff --git a/web/projects/ui/src/app/services/modal.service.ts b/web/projects/ui/src/app/services/modal.service.ts new file mode 100644 index 000000000..c34fce9a2 --- /dev/null +++ b/web/projects/ui/src/app/services/modal.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core' +import { ModalController } from '@ionic/angular' +import { DependentInfo } from 'src/app/types/dependent-info' +import { AppConfigPage } from 'src/app/modals/app-config/app-config.page' + +@Injectable({ + providedIn: 'root', +}) +export class ModalService { + constructor(private readonly modalCtrl: ModalController) {} + + async presentModalConfig(componentProps: ComponentProps): Promise { + const modal = await this.modalCtrl.create({ + component: AppConfigPage, + componentProps, + }) + await modal.present() + } +} + +interface ComponentProps { + pkgId: string + dependentInfo?: DependentInfo +} diff --git a/frontend/projects/ui/src/app/services/patch-data.service.ts b/web/projects/ui/src/app/services/patch-data.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/patch-data.service.ts rename to web/projects/ui/src/app/services/patch-data.service.ts diff --git a/frontend/projects/ui/src/app/services/patch-db/data-model.ts b/web/projects/ui/src/app/services/patch-db/data-model.ts similarity index 100% rename from frontend/projects/ui/src/app/services/patch-db/data-model.ts rename to web/projects/ui/src/app/services/patch-db/data-model.ts diff --git a/frontend/projects/ui/src/app/services/patch-db/local-storage-bootstrap.ts b/web/projects/ui/src/app/services/patch-db/local-storage-bootstrap.ts similarity index 100% rename from frontend/projects/ui/src/app/services/patch-db/local-storage-bootstrap.ts rename to web/projects/ui/src/app/services/patch-db/local-storage-bootstrap.ts diff --git a/frontend/projects/ui/src/app/services/patch-db/patch-db.factory.ts b/web/projects/ui/src/app/services/patch-db/patch-db.factory.ts similarity index 100% rename from frontend/projects/ui/src/app/services/patch-db/patch-db.factory.ts rename to web/projects/ui/src/app/services/patch-db/patch-db.factory.ts diff --git a/frontend/projects/ui/src/app/services/patch-db/patch-db.module.ts b/web/projects/ui/src/app/services/patch-db/patch-db.module.ts similarity index 100% rename from frontend/projects/ui/src/app/services/patch-db/patch-db.module.ts rename to web/projects/ui/src/app/services/patch-db/patch-db.module.ts diff --git a/frontend/projects/ui/src/app/services/patch-monitor.service.ts b/web/projects/ui/src/app/services/patch-monitor.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/patch-monitor.service.ts rename to web/projects/ui/src/app/services/patch-monitor.service.ts diff --git a/frontend/projects/ui/src/app/services/pkg-status-rendering.service.ts b/web/projects/ui/src/app/services/pkg-status-rendering.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/pkg-status-rendering.service.ts rename to web/projects/ui/src/app/services/pkg-status-rendering.service.ts diff --git a/frontend/projects/ui/src/app/services/split-pane.service.ts b/web/projects/ui/src/app/services/split-pane.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/split-pane.service.ts rename to web/projects/ui/src/app/services/split-pane.service.ts diff --git a/frontend/projects/ui/src/app/services/storage.service.ts b/web/projects/ui/src/app/services/storage.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/storage.service.ts rename to web/projects/ui/src/app/services/storage.service.ts diff --git a/frontend/projects/ui/src/app/services/theme-switcher.service.ts b/web/projects/ui/src/app/services/theme-switcher.service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/theme-switcher.service.ts rename to web/projects/ui/src/app/services/theme-switcher.service.ts diff --git a/frontend/projects/ui/src/app/services/time-service.ts b/web/projects/ui/src/app/services/time-service.ts similarity index 100% rename from frontend/projects/ui/src/app/services/time-service.ts rename to web/projects/ui/src/app/services/time-service.ts diff --git a/web/projects/ui/src/app/services/ui-launcher.service.ts b/web/projects/ui/src/app/services/ui-launcher.service.ts new file mode 100644 index 000000000..55559bcd3 --- /dev/null +++ b/web/projects/ui/src/app/services/ui-launcher.service.ts @@ -0,0 +1,18 @@ +import { Inject, Injectable } from '@angular/core' +import { WINDOW } from '@ng-web-apis/common' +import { PackageDataEntry } from 'src/app/services/patch-db/data-model' +import { ConfigService } from './config.service' + +@Injectable({ + providedIn: 'root', +}) +export class UiLauncherService { + constructor( + @Inject(WINDOW) private readonly windowRef: Window, + private readonly config: ConfigService, + ) {} + + launch(pkg: PackageDataEntry): void { + this.windowRef.open(this.config.launchableURL(pkg), '_blank', 'noreferrer') + } +} diff --git a/frontend/projects/ui/src/app/types/dependent-info.ts b/web/projects/ui/src/app/types/dependent-info.ts similarity index 100% rename from frontend/projects/ui/src/app/types/dependent-info.ts rename to web/projects/ui/src/app/types/dependent-info.ts diff --git a/web/projects/ui/src/app/types/mapped-backup-target.ts b/web/projects/ui/src/app/types/mapped-backup-target.ts new file mode 100644 index 000000000..13b51d4b5 --- /dev/null +++ b/web/projects/ui/src/app/types/mapped-backup-target.ts @@ -0,0 +1,5 @@ +export interface MappedBackupTarget { + id: string + hasValidBackup: boolean + entry: T +} diff --git a/frontend/projects/ui/src/app/types/pkg-info.ts b/web/projects/ui/src/app/types/pkg-info.ts similarity index 100% rename from frontend/projects/ui/src/app/types/pkg-info.ts rename to web/projects/ui/src/app/types/pkg-info.ts diff --git a/frontend/projects/ui/src/app/types/progress-data.ts b/web/projects/ui/src/app/types/progress-data.ts similarity index 100% rename from frontend/projects/ui/src/app/types/progress-data.ts rename to web/projects/ui/src/app/types/progress-data.ts diff --git a/frontend/projects/ui/src/app/util/animations.ts b/web/projects/ui/src/app/util/animations.ts similarity index 100% rename from frontend/projects/ui/src/app/util/animations.ts rename to web/projects/ui/src/app/util/animations.ts diff --git a/web/projects/ui/src/app/util/config-utilities.ts b/web/projects/ui/src/app/util/config-utilities.ts new file mode 100644 index 000000000..b105f56a0 --- /dev/null +++ b/web/projects/ui/src/app/util/config-utilities.ts @@ -0,0 +1,161 @@ +import { DefaultString } from '@start9labs/start-sdk/lib/config/configTypes' + +export class Range { + min?: number + max?: number + minInclusive!: boolean + maxInclusive!: boolean + + static from(s: string = '(*,*)'): Range { + const r = new Range() + r.minInclusive = s.startsWith('[') + r.maxInclusive = s.endsWith(']') + const [minStr, maxStr] = s.split(',').map(a => a.trim()) + r.min = minStr === '(*' ? undefined : Number(minStr.slice(1)) + r.max = maxStr === '*)' ? undefined : Number(maxStr.slice(0, -1)) + return r + } + + checkIncludes(n: number) { + if ( + this.hasMin() && + (this.min > n || (!this.minInclusive && this.min == n)) + ) { + throw new Error(this.minMessage()) + } + if ( + this.hasMax() && + (this.max < n || (!this.maxInclusive && this.max == n)) + ) { + throw new Error(this.maxMessage()) + } + } + + private hasMin(): this is Range & { min: number } { + return this.min !== undefined + } + + private hasMax(): this is Range & { max: number } { + return this.max !== undefined + } + + private minMessage(): string { + return `greater than${this.minInclusive ? ' or equal to' : ''} ${this.min}` + } + + private maxMessage(): string { + return `less than${this.maxInclusive ? ' or equal to' : ''} ${this.max}` + } +} + +export function getDefaultString(defaultSpec: DefaultString): string { + if (typeof defaultSpec === 'string') { + return defaultSpec + } else { + let s = '' + for (let i = 0; i < defaultSpec.len; i++) { + s = s + getRandomCharInSet(defaultSpec.charset) + } + + return s + } +} + +// a,g,h,A-Z,,,,- +function getRandomCharInSet(charset: string): string { + const set = stringToCharSet(charset) + let charIdx = Math.floor(Math.random() * set.len) + for (let range of set.ranges) { + if (range.len > charIdx) { + return String.fromCharCode(range.start.charCodeAt(0) + charIdx) + } + charIdx -= range.len + } + throw new Error('unreachable') +} + +function stringToCharSet(charset: string): CharSet { + let set: CharSet = { ranges: [], len: 0 } + let start: string | null = null + let end: string | null = null + let in_range = false + for (let char of charset) { + switch (char) { + case ',': + if (start !== null && end !== null) { + if (start!.charCodeAt(0) > end!.charCodeAt(0)) { + throw new Error('start > end of charset') + } + const len = end.charCodeAt(0) - start.charCodeAt(0) + 1 + set.ranges.push({ + start, + end, + len, + }) + set.len += len + start = null + end = null + in_range = false + } else if (start !== null && !in_range) { + set.len += 1 + set.ranges.push({ start, end: start, len: 1 }) + start = null + } else if (start !== null && in_range) { + end = ',' + } else if (start === null && end === null && !in_range) { + start = ',' + } else { + throw new Error('unexpected ","') + } + break + case '-': + if (start === null) { + start = '-' + } else if (!in_range) { + in_range = true + } else if (in_range && end === null) { + end = '-' + } else { + throw new Error('unexpected "-"') + } + break + default: + if (start === null) { + start = char + } else if (in_range && end === null) { + end = char + } else { + throw new Error(`unexpected "${char}"`) + } + } + } + if (start !== null && end !== null) { + if (start!.charCodeAt(0) > end!.charCodeAt(0)) { + throw new Error('start > end of charset') + } + const len = end.charCodeAt(0) - start.charCodeAt(0) + 1 + set.ranges.push({ + start, + end, + len, + }) + set.len += len + } else if (start !== null) { + set.len += 1 + set.ranges.push({ + start, + end: start, + len: 1, + }) + } + return set +} + +interface CharSet { + ranges: { + start: string + end: string + len: number + }[] + len: number +} diff --git a/frontend/projects/ui/src/app/util/configBuilderToSpec.ts b/web/projects/ui/src/app/util/configBuilderToSpec.ts similarity index 100% rename from frontend/projects/ui/src/app/util/configBuilderToSpec.ts rename to web/projects/ui/src/app/util/configBuilderToSpec.ts diff --git a/frontend/projects/ui/src/app/util/countries.json b/web/projects/ui/src/app/util/countries.json similarity index 99% rename from frontend/projects/ui/src/app/util/countries.json rename to web/projects/ui/src/app/util/countries.json index 72e285326..34ff9aa4a 100644 --- a/frontend/projects/ui/src/app/util/countries.json +++ b/web/projects/ui/src/app/util/countries.json @@ -249,4 +249,4 @@ "ZA": "South Africa", "ZM": "Zambia", "ZW": "Zimbabwe" -} \ No newline at end of file +} diff --git a/frontend/projects/ui/src/app/util/dry-update.ts b/web/projects/ui/src/app/util/dry-update.ts similarity index 100% rename from frontend/projects/ui/src/app/util/dry-update.ts rename to web/projects/ui/src/app/util/dry-update.ts diff --git a/frontend/projects/ui/src/app/util/get-package-data.ts b/web/projects/ui/src/app/util/get-package-data.ts similarity index 100% rename from frontend/projects/ui/src/app/util/get-package-data.ts rename to web/projects/ui/src/app/util/get-package-data.ts diff --git a/frontend/projects/ui/src/app/util/get-package-info.ts b/web/projects/ui/src/app/util/get-package-info.ts similarity index 100% rename from frontend/projects/ui/src/app/util/get-package-info.ts rename to web/projects/ui/src/app/util/get-package-info.ts diff --git a/frontend/projects/ui/src/app/util/get-project-id.ts b/web/projects/ui/src/app/util/get-project-id.ts similarity index 100% rename from frontend/projects/ui/src/app/util/get-project-id.ts rename to web/projects/ui/src/app/util/get-project-id.ts diff --git a/frontend/projects/ui/src/app/util/get-server-info.ts b/web/projects/ui/src/app/util/get-server-info.ts similarity index 100% rename from frontend/projects/ui/src/app/util/get-server-info.ts rename to web/projects/ui/src/app/util/get-server-info.ts diff --git a/frontend/projects/ui/src/app/util/has-deps.ts b/web/projects/ui/src/app/util/has-deps.ts similarity index 100% rename from frontend/projects/ui/src/app/util/has-deps.ts rename to web/projects/ui/src/app/util/has-deps.ts diff --git a/frontend/projects/ui/src/app/util/mask.ts b/web/projects/ui/src/app/util/mask.ts similarity index 100% rename from frontend/projects/ui/src/app/util/mask.ts rename to web/projects/ui/src/app/util/mask.ts diff --git a/frontend/projects/ui/src/app/util/package-loading-progress.ts b/web/projects/ui/src/app/util/package-loading-progress.ts similarity index 100% rename from frontend/projects/ui/src/app/util/package-loading-progress.ts rename to web/projects/ui/src/app/util/package-loading-progress.ts diff --git a/web/projects/ui/src/app/util/properties.util.ts b/web/projects/ui/src/app/util/properties.util.ts new file mode 100644 index 000000000..0d1d7e6f4 --- /dev/null +++ b/web/projects/ui/src/app/util/properties.util.ts @@ -0,0 +1,152 @@ +import { applyOperation } from 'fast-json-patch' +import matches, { + Parser, + shape, + string, + literal, + boolean, + deferred, + dictionary, + anyOf, + number, + arrayOf, +} from 'ts-matches' + +type ValidVersion = 1 | 2 + +type PropertiesV1 = typeof matchPropertiesV1._TYPE +type PackagePropertiesV1 = PropertiesV1[] +type PackagePropertiesV2 = { + [name: string]: PackagePropertyString | PackagePropertyObject +} +type PackagePropertiesVersionedData = T extends 1 + ? PackagePropertiesV1 + : T extends 2 + ? PackagePropertiesV2 + : never + +type PackagePropertyString = typeof matchPackagePropertyString._TYPE + +export type PackagePropertiesVersioned = { + version: T + data: PackagePropertiesVersionedData +} +export type PackageProperties = PackagePropertiesV2 + +const matchPropertiesV1 = shape( + { + name: string, + value: string, + description: string, + copyable: boolean, + qr: boolean, + }, + ['description', 'copyable', 'qr'], + { copyable: false, qr: false } as const, +) + +const [matchPackagePropertiesV2, setPPV2] = deferred() +const matchPackagePropertyString = shape( + { + type: literal('string'), + description: string, + value: string, + copyable: boolean, + qr: boolean, + masked: boolean, + }, + ['description', 'copyable', 'qr', 'masked'], + { + copyable: false, + qr: false, + masked: false, + } as const, +) +const matchPackagePropertyObject = shape( + { + type: literal('object'), + value: matchPackagePropertiesV2, + description: string, + }, + ['description'], +) + +const matchPropertyV2 = anyOf( + matchPackagePropertyString, + matchPackagePropertyObject, +) +type PackagePropertyObject = typeof matchPackagePropertyObject._TYPE +setPPV2(dictionary([string, matchPropertyV2])) + +const matchPackagePropertiesVersionedV1 = shape({ + version: number, + data: arrayOf(matchPropertiesV1), +}) +const matchPackagePropertiesVersionedV2 = shape({ + version: number, + data: dictionary([string, matchPropertyV2]), +}) + +export function parsePropertiesPermissive( + properties: unknown, + errorCallback: (err: Error) => any = console.warn, +): PackageProperties { + return matches(properties) + .when(matchPackagePropertiesVersionedV1, prop => + parsePropertiesV1Permissive(prop.data, errorCallback), + ) + .when(matchPackagePropertiesVersionedV2, prop => prop.data) + .when(matches.nill, {}) + .defaultToLazy(() => { + errorCallback(new TypeError(`value is not valid`)) + return {} + }) +} + +function parsePropertiesV1Permissive( + properties: unknown, + errorCallback: (err: Error) => any, +): PackageProperties { + if (!Array.isArray(properties)) { + errorCallback(new TypeError(`${properties} is not an array`)) + return {} + } + return properties.reduce( + (prev: PackagePropertiesV2, cur: unknown, idx: number) => { + const result = matchPropertiesV1.enumParsed(cur) + if ('value' in result) { + const value = result.value + prev[value.name] = { + type: 'string', + value: value.value, + description: value.description, + copyable: value.copyable, + qr: value.qr, + masked: false, + } + } else { + const error = result.error + const message = Parser.validatorErrorAsString(error) + const dataPath = error.keys.map(removeQuotes).join('/') + errorCallback(new Error(`/data/${idx}: ${message}`)) + if (dataPath) { + applyOperation(cur, { + op: 'replace', + path: `/${dataPath}`, + value: undefined, + }) + } + } + return prev + }, + {}, + ) +} + +const removeRegex = /('|")/ +function removeQuotes(x: string) { + while (removeRegex.test(x)) { + x = x.replace(removeRegex, '') + } + return x +} diff --git a/frontend/projects/ui/src/app/util/rxjs.util.ts b/web/projects/ui/src/app/util/rxjs.util.ts similarity index 100% rename from frontend/projects/ui/src/app/util/rxjs.util.ts rename to web/projects/ui/src/app/util/rxjs.util.ts diff --git a/frontend/projects/ui/src/app/util/web.util.ts b/web/projects/ui/src/app/util/web.util.ts similarity index 100% rename from frontend/projects/ui/src/app/util/web.util.ts rename to web/projects/ui/src/app/util/web.util.ts diff --git a/frontend/projects/ui/src/environments/environment.prod.ts b/web/projects/ui/src/environments/environment.prod.ts similarity index 100% rename from frontend/projects/ui/src/environments/environment.prod.ts rename to web/projects/ui/src/environments/environment.prod.ts diff --git a/frontend/projects/ui/src/environments/environment.ts b/web/projects/ui/src/environments/environment.ts similarity index 100% rename from frontend/projects/ui/src/environments/environment.ts rename to web/projects/ui/src/environments/environment.ts diff --git a/web/projects/ui/src/globals.d.ts b/web/projects/ui/src/globals.d.ts new file mode 100644 index 000000000..d8024e92b --- /dev/null +++ b/web/projects/ui/src/globals.d.ts @@ -0,0 +1 @@ +declare module '*.md' diff --git a/frontend/projects/ui/src/index.html b/web/projects/ui/src/index.html similarity index 100% rename from frontend/projects/ui/src/index.html rename to web/projects/ui/src/index.html diff --git a/frontend/projects/ui/src/main.ts b/web/projects/ui/src/main.ts similarity index 85% rename from frontend/projects/ui/src/main.ts rename to web/projects/ui/src/main.ts index 3d8855b64..11a215811 100644 --- a/frontend/projects/ui/src/main.ts +++ b/web/projects/ui/src/main.ts @@ -8,5 +8,6 @@ if (environment.production) { enableProdMode() } -platformBrowserDynamic().bootstrapModule(AppModule) +platformBrowserDynamic() + .bootstrapModule(AppModule) .catch(err => console.error(err)) diff --git a/frontend/projects/ui/src/manifest.webmanifest b/web/projects/ui/src/manifest.webmanifest similarity index 100% rename from frontend/projects/ui/src/manifest.webmanifest rename to web/projects/ui/src/manifest.webmanifest diff --git a/frontend/projects/ui/src/polyfills.ts b/web/projects/ui/src/polyfills.ts similarity index 100% rename from frontend/projects/ui/src/polyfills.ts rename to web/projects/ui/src/polyfills.ts diff --git a/frontend/projects/ui/src/styles.scss b/web/projects/ui/src/styles.scss similarity index 100% rename from frontend/projects/ui/src/styles.scss rename to web/projects/ui/src/styles.scss diff --git a/frontend/projects/ui/src/zone-flags.ts b/web/projects/ui/src/zone-flags.ts similarity index 100% rename from frontend/projects/ui/src/zone-flags.ts rename to web/projects/ui/src/zone-flags.ts diff --git a/frontend/projects/ui/tsconfig.json b/web/projects/ui/tsconfig.json similarity index 100% rename from frontend/projects/ui/tsconfig.json rename to web/projects/ui/tsconfig.json diff --git a/frontend/proxy.conf-sample.json b/web/proxy.conf-sample.json similarity index 100% rename from frontend/proxy.conf-sample.json rename to web/proxy.conf-sample.json diff --git a/frontend/tsconfig.json b/web/tsconfig.json similarity index 100% rename from frontend/tsconfig.json rename to web/tsconfig.json diff --git a/frontend/tsconfig.lib.json b/web/tsconfig.lib.json similarity index 100% rename from frontend/tsconfig.lib.json rename to web/tsconfig.lib.json diff --git a/frontend/tslint.json b/web/tslint.json similarity index 100% rename from frontend/tslint.json rename to web/tslint.json