diff --git a/.github/scripts/add-signing-public-key.ts b/.github/scripts/add-signing-public-key.ts new file mode 100644 index 0000000..84c3b09 --- /dev/null +++ b/.github/scripts/add-signing-public-key.ts @@ -0,0 +1,39 @@ +/** + * @brief Part of the automatic updates pipeline. This will read the environment variable + * `TAURI_SIGNING_PUBLIC_KEY` and attach it to the `tauri.conf.json` file. + * + * @see https://v2.tauri.app/plugin/updater/ + * + * @note This script is intended to be run in a GitHub Actions workflow, and not locally. It + * will overwrite the `tauri.conf.json` file. This change is not meant to be committed. + */ + +import * as fs from "fs"; + +/** + * @brief We use the environment variable `TAURI_SIGNING_PUBLIC_KEY` + */ +const PUBLIC_KEY = process.env.TAURI_SIGNING_PUBLIC_KEY; + +/** + * @brief Path to the Tauri configuration file. + */ +const TAURI_CONFIG_PATH = "torii-desktop/tauri.conf.json"; + +/** + * @brief Appends the information as specified by the Tauri Updater plugin to the Tauri + * configuration file. + * + * @see + */ +function appendUpdaterConfig() { + const tauriConfig = JSON.parse(fs.readFileSync(TAURI_CONFIG_PATH, "utf-8")); + tauriConfig.bundle.createUpdaterArtifacts = true; + tauriConfig.plugins.updater.pubkey = PUBLIC_KEY; + fs.writeFileSync(TAURI_CONFIG_PATH, JSON.stringify(tauriConfig, null, 4)); + + console.log('Public Key: ', PUBLIC_KEY); +} + +// Run the change updater configuration. +appendUpdaterConfig(); \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8769f9d..a987870 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,6 +15,7 @@ jobs: publish-tauri: permissions: contents: write + environment: Publish Environment strategy: fail-fast: false matrix: @@ -78,9 +79,16 @@ jobs: if: matrix.platform == 'windows-latest' run: npm run fix-windows-version + - name: Inject signing public key into config + run: npm run add-signing-public-key + env: + TAURI_SIGNING_PUBLIC_KEY: ${{ vars.TAURI_SIGNING_PUBLIC_KEY }} + - uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + # TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} with: tagName: app-v${{ steps.get-version.outputs.version }} releaseName: 'App v${{ steps.get-version.outputs.version }}' diff --git a/Cargo.lock b/Cargo.lock index 77f1905..fd59fb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,15 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "arrayvec" version = "0.7.6" @@ -850,6 +859,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "derive_more" version = "2.1.1" @@ -1171,6 +1191,16 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -2312,6 +2342,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minisign-verify" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2569,6 +2605,18 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-osa-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" +dependencies = [ + "bitflags 2.13.0", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + [[package]] name = "objc2-quartz-core" version = "0.3.2" @@ -2665,6 +2713,20 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "osakit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" +dependencies = [ + "objc2", + "objc2-foundation", + "objc2-osa-kit", + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "pango" version = "0.18.3" @@ -3398,6 +3460,7 @@ checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "aws-lc-rs", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -4073,6 +4136,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -4314,6 +4388,16 @@ dependencies = [ "zbus", ] +[[package]] +name = "tauri-plugin-process" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a" +dependencies = [ + "tauri", + "tauri-plugin", +] + [[package]] name = "tauri-plugin-store" version = "2.4.3" @@ -4330,6 +4414,39 @@ dependencies = [ "tracing", ] +[[package]] +name = "tauri-plugin-updater" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806d9dac662c2e4594ff03c647a552f2c9bd544e7d0f683ec58f872f952ce4af" +dependencies = [ + "base64 0.22.1", + "dirs", + "flate2", + "futures-util", + "http", + "infer", + "log", + "minisign-verify", + "osakit", + "percent-encoding", + "reqwest", + "rustls", + "semver", + "serde", + "serde_json", + "tar", + "tauri", + "tauri-plugin", + "tempfile", + "thiserror 2.0.18", + "time", + "tokio", + "url", + "windows-sys 0.60.2", + "zip", +] + [[package]] name = "tauri-runtime" version = "2.11.3" @@ -4735,7 +4852,9 @@ dependencies = [ "tauri-plugin-dialog", "tauri-plugin-log", "tauri-plugin-opener", + "tauri-plugin-process", "tauri-plugin-store", + "tauri-plugin-updater", ] [[package]] @@ -5942,6 +6061,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "yoke" version = "0.8.3" @@ -6106,6 +6235,18 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "zip" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" +dependencies = [ + "arbitrary", + "crc32fast", + "indexmap 2.14.0", + "memchr", +] + [[package]] name = "zmij" version = "1.0.21" diff --git a/ROADMAP.md b/ROADMAP.md index afa13d5..a66cfec 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -96,6 +96,9 @@ The first stage of the project is to create a simple file browser like applicati Due to my Bachelors' thesis I took a 3 week break from Torii here and `dev9` should be a small update to bring back the pace. +- [x] Add updater artifacts (build signatures) to CI/CD. +- [x] Add a button which checks if an update is available. (Not Tested!) + ### `v0.0.0-dev10` - [ ] Edit Mode: WYSIWYG if provided, allows to edit article, drag and drop diff --git a/package-lock.json b/package-lock.json index f8f3f83..ace1f3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ ], "devDependencies": { "@tauri-apps/cli": "^2.11.1", - "@types/node": "^25.9.3", + "@types/node": "^25.9.5", "@vitejs/plugin-vue": "^6.0.7", "tsx": "^4.22.4", "vite": "^8.0.16", @@ -1096,6 +1096,15 @@ "@tauri-apps/api": "^2.11.0" } }, + "node_modules/@tauri-apps/plugin-process": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-process/-/plugin-process-2.3.1.tgz", + "integrity": "sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.8.0" + } + }, "node_modules/@tauri-apps/plugin-store": { "version": "2.4.3", "license": "MIT OR Apache-2.0", @@ -1103,6 +1112,15 @@ "@tauri-apps/api": "^2.11.0" } }, + "node_modules/@tauri-apps/plugin-updater": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-updater/-/plugin-updater-2.10.1.tgz", + "integrity": "sha512-NFYMg+tWOZPJdzE/PpFj2qfqwAWwNS3kXrb1tm1gnBJ9mYzZ4WDRrwy8udzWoAnfGCHLuePNLY1WVCNHnh3eRA==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.10.1" + } + }, "node_modules/@tiptap/core": { "version": "3.27.1", "license": "MIT", @@ -1623,7 +1641,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.9.4", + "version": "25.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", + "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", "dev": true, "license": "MIT", "dependencies": { @@ -11396,7 +11416,9 @@ "@tauri-apps/api": "^2.11.0", "@tauri-apps/plugin-dialog": "^2.7.1", "@tauri-apps/plugin-opener": "^2.5.4", + "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-store": "^2.4.3", + "@tauri-apps/plugin-updater": "^2.10.1", "@tiptap/extension-list": "^3.27.1", "@tiptap/markdown": "^3.27.1", "@tiptap/pm": "^3.27.1", diff --git a/package.json b/package.json index 1da485e..2c99465 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ ], "devDependencies": { "@tauri-apps/cli": "^2.11.1", - "@types/node": "^25.9.3", + "@types/node": "^25.9.5", "@vitejs/plugin-vue": "^6.0.7", "tsx": "^4.22.4", "vite": "^8.0.16", @@ -18,6 +18,7 @@ "lint": "npm run lint --workspace=torii-client", "tauri": "tauri", "fix-windows-version": "tsx .github/scripts/fix-windows-versioning.ts", + "add-signing-public-key": "tsx .github/scripts/add-signing-public-key.ts ", "version": "tsx .github/scripts/print-tauri-version.ts", "docs": "npm run docs --workspace=torii-client" } diff --git a/torii-client/package.json b/torii-client/package.json index 159ad08..2b7e99f 100644 --- a/torii-client/package.json +++ b/torii-client/package.json @@ -13,7 +13,9 @@ "@tauri-apps/api": "^2.11.0", "@tauri-apps/plugin-dialog": "^2.7.1", "@tauri-apps/plugin-opener": "^2.5.4", + "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-store": "^2.4.3", + "@tauri-apps/plugin-updater": "^2.10.1", "@tiptap/extension-list": "^3.27.1", "@tiptap/markdown": "^3.27.1", "@tiptap/pm": "^3.27.1", diff --git a/torii-client/src/components/UpdateButton.vue b/torii-client/src/components/UpdateButton.vue new file mode 100644 index 0000000..fe09886 --- /dev/null +++ b/torii-client/src/components/UpdateButton.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/torii-client/src/components/article/MarkdownEditor.vue b/torii-client/src/components/article/MarkdownEditor.vue index c490e63..57fbd9a 100644 --- a/torii-client/src/components/article/MarkdownEditor.vue +++ b/torii-client/src/components/article/MarkdownEditor.vue @@ -37,7 +37,7 @@ import { type SuggestionItem, } from './autocomplete-extension'; import MarkdownEditorAutocomplete from './MarkdownEditorAutocomplete.vue'; -import { Record } from 'types'; +import type { Record } from '../../types.d.ts'; const props = defineProps<{ record: Record; diff --git a/torii-client/src/views/HomeView.vue b/torii-client/src/views/HomeView.vue index 20970e4..1b0fa57 100644 --- a/torii-client/src/views/HomeView.vue +++ b/torii-client/src/views/HomeView.vue @@ -13,10 +13,15 @@
- {{ $t('app.menu.home') }} - - {{ $t('app.version.verbose', { version }) }} - +
+ {{ $t('app.menu.home') }} + + {{ $t('app.version.verbose', { version }) }} + +
+
+ +
@@ -29,6 +34,7 @@ import { SettingsOutline } from '@vicons/ionicons5'; import LanguageSelect from '@/components/LanguageSelect.vue'; import RecentProjectsView from './RecentProjectsView.vue'; import { openSettingsWindow } from '../composables/settings-window.ts'; +import UpdateButton from '@/components/UpdateButton.vue'; const version = ref('Invalid Version'); @@ -71,9 +77,24 @@ onMounted(async () => { .view-home-content { display: flex; flex-direction: column; - align-items: center; - justify-content: center; flex: 1; + + .view-home-title { + display: flex; + flex-direction: column; + justify-self: center; + align-items: center; + justify-content: center; + flex: 1; + } + + .view-home-update { + display: flex; + flex-direction: row; + justify-content: center; + justify-self: end; + margin-bottom: 16px; + } } } diff --git a/torii-client/src/views/project/ProjectView.vue b/torii-client/src/views/project/ProjectView.vue index 337c60b..6b4d5e4 100644 --- a/torii-client/src/views/project/ProjectView.vue +++ b/torii-client/src/views/project/ProjectView.vue @@ -129,7 +129,7 @@ import { useSettingsStore } from '@/stores/settings'; // Components import MarkdownEditor from '../../components/article/MarkdownEditor.vue'; import ImageEditor from '../../components/image/ImageEditor.vue'; -import { Record } from 'types'; +import type { Record } from '../../types.d.ts'; import UIFileTree from '@/ui/UIFileTree.vue'; import UISelect from '@/ui/UISelect.vue'; import { TreeNode } from 'ui/UITree.vue'; diff --git a/torii-desktop/Cargo.toml b/torii-desktop/Cargo.toml index c991930..eb43ac5 100644 --- a/torii-desktop/Cargo.toml +++ b/torii-desktop/Cargo.toml @@ -22,3 +22,7 @@ tauri-plugin-dialog = "2.7" tauri-plugin-cors-fetch = "5.0.0" tauri-plugin-store = "2.4.3" tauri-plugin-opener = "2.5.4" +tauri-plugin-process = "2.3.1" + +[target.'cfg(any(target_os = "macos", windows, target_os = "linux"))'.dependencies] +tauri-plugin-updater = "2.10.1" diff --git a/torii-desktop/capabilities/default.json b/torii-desktop/capabilities/default.json index cfafa46..91003e4 100644 --- a/torii-desktop/capabilities/default.json +++ b/torii-desktop/capabilities/default.json @@ -17,6 +17,8 @@ "cors-fetch:default", "store:default", "opener:allow-default-urls", - "opener:allow-open-url" + "opener:allow-open-url", + "updater:allow-check", + "process:allow-restart" ] } \ No newline at end of file diff --git a/torii-desktop/src/lib.rs b/torii-desktop/src/lib.rs index 0f1f18f..b5a4342 100644 --- a/torii-desktop/src/lib.rs +++ b/torii-desktop/src/lib.rs @@ -21,7 +21,9 @@ pub fn run() { .plugin(tauri_plugin_cors_fetch::init()) .plugin(tauri_plugin_store::Builder::default().build()) .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_process::init()) .setup(enable_logging) + .setup(enable_update_artifacts) .invoke_handler(tauri::generate_handler![ recent::list_recent_projects, recent::add_recent_project, @@ -53,3 +55,23 @@ pub fn enable_logging(app: &mut App) -> Result<(), Box> { } Ok(()) } + +/// Enables updater artifacts for the application. This will build +/// application signatures which are used to update older clients. +pub fn enable_update_artifacts(app: &mut App) -> Result<(), Box> { + #[cfg(desktop)] + { + #[allow(unused)] + let res = app + .handle() + .plugin(tauri_plugin_updater::Builder::new().build()); + + // In development mode, we can safely ignore this errors. In + // releases builds however, we expect this to work. + #[cfg(not(debug_assertions))] + if let Err(err) = res { + println!("{err}"); + } + } + Ok(()) +} diff --git a/torii-desktop/tauri.conf.json b/torii-desktop/tauri.conf.json index d31dfd1..3b69671 100644 --- a/torii-desktop/tauri.conf.json +++ b/torii-desktop/tauri.conf.json @@ -43,5 +43,12 @@ "../torii-workspaces/writing-theory": "workspaces/writing-theory/", "../torii-workspaces/workspaces.json": "workspaces/workspaces.json" } + }, + "plugins": { + "updater": { + "endpoints": [ + "https://github.com/Anatoly03/Torii/releases/latest/download/latest.json" + ] + } } } diff --git a/torii-workspaces/welcome/Changelog.md b/torii-workspaces/welcome/Changelog.md index 0b25691..632dc40 100644 --- a/torii-workspaces/welcome/Changelog.md +++ b/torii-workspaces/welcome/Changelog.md @@ -4,7 +4,8 @@ ### [v0.0.0-dev9](https://github.com/Anatoly03/Torii/releases/tag/app-v0.0.0-dev9) -- TBA +- Add "Preview Mode" to record footer, which disable editing and hides image placeholder grids. +- Add an update information button in the welcome screen. *This button has not been tested yet! We will see when dev10 releases if it works.* ---