@synopackageland/templates 0.35.5 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -17
- package/package.json +1 -1
- package/templates/compose/dsm-package.yaml +1 -1
- package/templates/native-go/README.md +2 -2
- package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +1 -1
- package/templates/native-go/backend/go.mod +1 -1
- package/templates/native-go/backend/go.sum +2 -2
- package/templates/native-go/backend/internal/app/background.go +10 -12
- package/templates/native-go/backend/internal/app/background_inbox_test.go +37 -0
- package/templates/native-go/backend/internal/app/background_owner.go +14 -0
- package/templates/native-go/backend/internal/app/background_owner_test.go +2 -2
- package/templates/native-go/backend/internal/app/background_test.go +27 -8
- package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +1 -1
- package/templates/native-go-delegate/frontend/test/capability-panels.test.ts +1 -0
- package/templates/native-go-vue/frontend/package-lock.json +658 -9
- package/templates/native-go-vue/frontend/package.json +2 -2
- package/templates/native-node/README.md +2 -2
- package/templates/native-node/backend/package-lock.json +2 -2
- package/templates/native-node/dsm-package.yaml +1 -1
- package/templates/native-node-delegate/backend/src/delegate.ts +20 -8
- package/templates/native-node-delegate/backend/test/delegate.test.ts +18 -9
- package/templates/native-python/README.md +2 -2
- package/templates/native-python/dsm-package.yaml +1 -1
- package/templates/native-python-delegate/backend/app/delegate.py +19 -7
- package/templates/native-python-delegate/backend/tests/test_delegate.py +18 -8
- package/templates/native-rust/README.md +2 -2
- package/templates/native-rust/backend/Cargo.lock +2 -2
- package/templates/native-rust/backend/Cargo.toml +1 -1
- package/templates/native-rust-delegate/backend/Cargo.lock +203 -0
- package/templates/native-rust-delegate/backend/Cargo.toml +17 -0
- package/templates/native-rust-delegate/backend/src/delegate.rs +78 -23
|
@@ -17,7 +17,7 @@ DSM main menu → DSM window (ui/app.js)
|
|
|
17
17
|
|
|
18
18
|
## Requests and long work
|
|
19
19
|
|
|
20
|
-
SDK/App 0.
|
|
20
|
+
SDK/App 0.41.1 defaults to 300-second requests and a 302-second browser wait.
|
|
21
21
|
Explicit `backend.timeout_seconds` and earlier parent deadlines still apply;
|
|
22
22
|
rebuild the App to use the new SDK. For long NAS work, enable the existing jobs
|
|
23
23
|
capability: return admission and the original job ID promptly, execute in the
|
|
@@ -27,7 +27,7 @@ last queued/running state intact. After a lost admission reply, reuse the same
|
|
|
27
27
|
idempotency key and input instead of replaying a mutation with a new key.
|
|
28
28
|
Jobs default to 30 minutes; approved executor limits remain separate. ctl keeps
|
|
29
29
|
its 62-second transport default; use an explicit `--timeout` or an existing
|
|
30
|
-
nonblocking job. See the SDK's [request deadline contract](https://github.com/synopackageland/syno-pkg-land-sdk/blob/v0.
|
|
30
|
+
nonblocking job. See the SDK's [request deadline contract](https://github.com/synopackageland/syno-pkg-land-sdk/blob/v0.41.1/docs/request-deadlines.md).
|
|
31
31
|
|
|
32
32
|
## Quick start
|
|
33
33
|
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
//
|
|
3
3
|
// The browser picks the destination with the SDK's Background saves page and
|
|
4
4
|
// sends its delegation ID; the executor checks that it is the caller's grant
|
|
5
|
-
// and writes the file as the caller, never as root.
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
import {
|
|
5
|
+
// and writes the file as the caller, never as root. An admitted or uncertain
|
|
6
|
+
// save retries the same file and job ID; the executor copies it at most once.
|
|
7
|
+
// A new source rejected because its delegation is denied is removed.
|
|
8
|
+
import { createHash } from 'node:crypto'
|
|
9
|
+
import { mkdirSync, statSync, writeFileSync, unlinkSync } from 'node:fs'
|
|
9
10
|
import { join } from 'node:path'
|
|
10
11
|
import { AppError, type App, type Context } from '@synopackageland/app'
|
|
11
12
|
import { strings } from './params.js'
|
|
@@ -18,18 +19,29 @@ export function register(app: App, cfg: Config): void {
|
|
|
18
19
|
app.method('report.save', (ctx, params) => save(cfg, ctx, params))
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
function save(cfg: Config, ctx: Context, params: unknown) {
|
|
22
|
+
async function save(cfg: Config, ctx: Context, params: unknown) {
|
|
22
23
|
const { delegation_id, job_id } = strings(params, 'delegation_id', 'job_id')
|
|
23
|
-
if (!JOB_ID.test(job_id)) throw AppError.badRequest("job_id must be 1 to 128 letters, digits, '.', '_' or '-'")
|
|
24
|
+
if (!JOB_ID.test(job_id) || !JOB_ID.test(delegation_id)) throw AppError.badRequest("job_id must be 1 to 128 letters, digits, '.', '_' or '-'")
|
|
24
25
|
const name = `report-${job_id}.txt`
|
|
25
26
|
// The runtime's delegate service moves files from here.
|
|
26
|
-
const
|
|
27
|
+
const owner = createHash('sha256').update(`${ctx.user}\0${delegation_id}`).digest('hex')
|
|
28
|
+
const scopedJob = createHash('sha256').update(`${ctx.user}\0${delegation_id}\0${job_id}`).digest('hex') + `-${owner.slice(0, 32)}`
|
|
29
|
+
const relative = `owners/${owner}/${name}`
|
|
30
|
+
const staging = join(cfg.dataDir, 'executor-staging', 'owners', owner)
|
|
27
31
|
mkdirSync(staging, { recursive: true, mode: 0o700 })
|
|
28
32
|
const path = join(staging, name)
|
|
33
|
+
let created = false
|
|
29
34
|
try {
|
|
30
35
|
writeFileSync(path, `Report for ${ctx.user}, ${new Date().toISOString().replace(/\.\d+Z$/, 'Z')}\n`, { flag: 'wx', mode: 0o600 })
|
|
36
|
+
created = true
|
|
31
37
|
} catch (e) {
|
|
32
38
|
if ((e as NodeJS.ErrnoException).code !== 'EEXIST') throw e
|
|
33
39
|
}
|
|
34
|
-
|
|
40
|
+
try {
|
|
41
|
+
return await service(ctx, 'delegate.move_from_staging', { delegation_id, job_id: scopedJob, staging: relative, name, size: statSync(path).size })
|
|
42
|
+
} catch (e) {
|
|
43
|
+
// A transport failure may already have been admitted; keep its source.
|
|
44
|
+
if (created && e instanceof AppError && e.code === 'DELEGATION_DENIED') unlinkSync(path)
|
|
45
|
+
throw e
|
|
46
|
+
}
|
|
35
47
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from 'node:assert/strict'
|
|
2
|
-
import { existsSync, mkdtempSync, readFileSync, rmSync, statSync } from 'node:fs'
|
|
2
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, readdirSync } from 'node:fs'
|
|
3
3
|
import { tmpdir } from 'node:os'
|
|
4
4
|
import { join } from 'node:path'
|
|
5
5
|
import { afterEach, beforeEach, test } from 'node:test'
|
|
@@ -23,23 +23,32 @@ const save = (user = 'alice', move: Services[string] = () => SAVED) =>
|
|
|
23
23
|
test('report.save moves a private report to the caller\'s destination', async () => {
|
|
24
24
|
const reply = await save()
|
|
25
25
|
assert.deepEqual(reply.data, SAVED)
|
|
26
|
-
const path = join(staging,
|
|
26
|
+
const path = join(staging, (reply.services[0][1] as {staging: string}).staging)
|
|
27
27
|
assert.match(readFileSync(path, 'utf8'), /alice/)
|
|
28
28
|
assert.equal(statSync(path).mode & 0o777, 0o600)
|
|
29
|
-
const move = { delegation_id: 'd1', job_id:
|
|
29
|
+
const move = { delegation_id: 'd1', job_id: (reply.services[0][1] as {job_id: string}).job_id, staging: (reply.services[0][1] as {staging: string}).staging, name: 'report-job-1.txt', size: statSync(path).size }
|
|
30
30
|
assert.deepEqual(reply.services, [['delegate.move_from_staging', move]])
|
|
31
|
+
assert.ok(move.job_id.endsWith(`-${move.staging.split('/')[1].slice(0, 32)}`))
|
|
31
32
|
})
|
|
32
33
|
|
|
33
|
-
test('
|
|
34
|
+
test('retries reuse only the same owner and grant source', async () => {
|
|
34
35
|
const first = (await save()).services
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
assert.
|
|
36
|
+
const params = first[0][1] as {staging: string; job_id: string}
|
|
37
|
+
const report = readFileSync(join(staging, params.staging), 'utf8')
|
|
38
|
+
assert.deepEqual((await save()).services, first)
|
|
39
|
+
const other = (await save('bob')).services[0][1] as {staging: string; job_id: string}
|
|
40
|
+
assert.notEqual(other.staging, params.staging)
|
|
41
|
+
assert.notEqual(other.job_id, params.job_id)
|
|
42
|
+
assert.match(readFileSync(join(staging, other.staging), 'utf8'), /bob/)
|
|
43
|
+
assert.equal(readFileSync(join(staging, params.staging), 'utf8'), report)
|
|
38
44
|
})
|
|
39
45
|
|
|
40
|
-
test('
|
|
41
|
-
const reply = await save('alice', () => { throw new Refusal('DELEGATION_DENIED', 'The destination is no longer allowed
|
|
46
|
+
test('definitive rejection removes new source but a timeout keeps it', async () => {
|
|
47
|
+
const reply = await save('alice', () => { throw new Refusal('DELEGATION_DENIED', 'The destination is no longer allowed') })
|
|
42
48
|
assert.equal(reply.error?.code, 'DELEGATION_DENIED')
|
|
49
|
+
assert.equal(readdirSync(staging, { recursive: true }).filter(p => String(p).endsWith('.txt')).length, 0)
|
|
50
|
+
const unknown = await save('alice', () => { throw new Refusal('EXECUTOR_TIMEOUT', 'The outcome is unknown') })
|
|
51
|
+
assert.equal(existsSync(join(staging, (unknown.services[0][1] as {staging: string}).staging)), true)
|
|
43
52
|
})
|
|
44
53
|
|
|
45
54
|
test('report.save refuses invalid params before writing', async () => {
|
|
@@ -17,7 +17,7 @@ DSM main menu → DSM window (ui/app.js)
|
|
|
17
17
|
|
|
18
18
|
## Requests and long work
|
|
19
19
|
|
|
20
|
-
SDK/App 0.
|
|
20
|
+
SDK/App 0.41.1 defaults to 300-second requests and a 302-second browser wait.
|
|
21
21
|
Explicit `backend.timeout_seconds` and earlier parent deadlines still apply;
|
|
22
22
|
rebuild the App to use the new SDK. For long NAS work, enable the existing jobs
|
|
23
23
|
capability: return admission and the original job ID promptly, execute in the
|
|
@@ -27,7 +27,7 @@ last queued/running state intact. After a lost admission reply, reuse the same
|
|
|
27
27
|
idempotency key and input instead of replaying a mutation with a new key.
|
|
28
28
|
Jobs default to 30 minutes; approved executor limits remain separate. ctl keeps
|
|
29
29
|
its 62-second transport default; use an explicit `--timeout` or an existing
|
|
30
|
-
nonblocking job. See the SDK's [request deadline contract](https://github.com/synopackageland/syno-pkg-land-sdk/blob/v0.
|
|
30
|
+
nonblocking job. See the SDK's [request deadline contract](https://github.com/synopackageland/syno-pkg-land-sdk/blob/v0.41.1/docs/request-deadlines.md).
|
|
31
31
|
|
|
32
32
|
## Quick start
|
|
33
33
|
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
The browser picks the destination with the SDK's Background saves page and
|
|
4
4
|
sends its delegation ID; the executor checks that it is the caller's grant
|
|
5
|
-
and writes the file as the caller, never as root.
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
and writes the file as the caller, never as root. An admitted or uncertain
|
|
6
|
+
save retries the same file and job ID; the executor copies it at most once.
|
|
7
|
+
A new source rejected because its delegation is denied is removed.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
+
import hashlib
|
|
10
11
|
import os
|
|
11
12
|
import re
|
|
12
13
|
import time
|
|
@@ -24,19 +25,30 @@ def register(app, cfg):
|
|
|
24
25
|
|
|
25
26
|
def save(cfg, ctx, params):
|
|
26
27
|
p = fields(params, delegation_id=str, job_id=str)
|
|
27
|
-
if not JOB_ID.match(p["job_id"]):
|
|
28
|
+
if not JOB_ID.match(p["job_id"]) or not JOB_ID.match(p["delegation_id"]):
|
|
28
29
|
raise Error.bad_request("job_id must be 1 to 128 letters, digits, '.', '_' or '-'")
|
|
29
30
|
name = "report-%s.txt" % p["job_id"]
|
|
30
31
|
# The runtime's delegate service moves files from here.
|
|
31
|
-
|
|
32
|
+
owner = hashlib.sha256((ctx.user + "\0" + p["delegation_id"]).encode("utf-8")).hexdigest()
|
|
33
|
+
job_id = hashlib.sha256((ctx.user + "\0" + p["delegation_id"] + "\0" + p["job_id"]).encode("utf-8")).hexdigest() + "-" + owner[:32]
|
|
34
|
+
relative = "owners/%s/%s" % (owner, name)
|
|
35
|
+
staging = os.path.join(cfg.data_dir, "executor-staging", "owners", owner)
|
|
32
36
|
os.makedirs(staging, mode=0o700, exist_ok=True)
|
|
33
37
|
path = os.path.join(staging, name)
|
|
38
|
+
created = False
|
|
34
39
|
try:
|
|
35
40
|
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
|
|
36
41
|
except FileExistsError:
|
|
37
42
|
pass
|
|
38
43
|
else:
|
|
44
|
+
created = True
|
|
39
45
|
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
|
40
46
|
f.write("Report for %s, %s\n" % (ctx.user, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())))
|
|
41
|
-
move = {"delegation_id": p["delegation_id"], "job_id":
|
|
42
|
-
|
|
47
|
+
move = {"delegation_id": p["delegation_id"], "job_id": job_id, "staging": relative, "name": name, "size": os.path.getsize(path)}
|
|
48
|
+
try:
|
|
49
|
+
return ctx.runtime("delegate.move_from_staging", move)
|
|
50
|
+
except Error as err:
|
|
51
|
+
# A transport failure may already have been admitted; keep its source.
|
|
52
|
+
if created and err.code == "DELEGATION_DENIED":
|
|
53
|
+
os.unlink(path)
|
|
54
|
+
raise
|
|
@@ -24,27 +24,37 @@ class DelegateTest(unittest.TestCase):
|
|
|
24
24
|
def test_save_moves_a_private_report_to_the_callers_destination(self):
|
|
25
25
|
reply = self.save()
|
|
26
26
|
self.assertEqual(reply.data, SAVED)
|
|
27
|
-
path = os.path.join(self.staging,
|
|
27
|
+
path = os.path.join(self.staging, reply.services[0][1]["staging"])
|
|
28
28
|
with open(path, encoding="utf-8") as f:
|
|
29
29
|
self.assertIn("alice", f.read())
|
|
30
30
|
self.assertEqual(stat.S_IMODE(os.stat(path).st_mode), 0o600)
|
|
31
|
-
move = {"delegation_id": "d1", "job_id":
|
|
31
|
+
move = {"delegation_id": "d1", "job_id": reply.services[0][1]["job_id"], "staging": reply.services[0][1]["staging"], "name": "report-job-1.txt", "size": os.path.getsize(path)}
|
|
32
32
|
self.assertEqual(reply.services, [("delegate.move_from_staging", move)])
|
|
33
|
+
self.assertTrue(move["job_id"].endswith("-" + move["staging"].split("/")[1][:32]))
|
|
33
34
|
|
|
34
|
-
def
|
|
35
|
+
def test_retries_reuse_only_the_same_owners_file(self):
|
|
35
36
|
first = self.save().services
|
|
36
|
-
path = os.path.join(self.staging,
|
|
37
|
+
path = os.path.join(self.staging, first[0][1]["staging"])
|
|
37
38
|
with open(path, encoding="utf-8") as f:
|
|
38
39
|
report = f.read()
|
|
39
|
-
self.assertEqual(self.save(
|
|
40
|
+
self.assertEqual(self.save().services, first)
|
|
41
|
+
other = self.save(user="bob").services
|
|
42
|
+
self.assertNotEqual(other[0][1]["staging"], first[0][1]["staging"])
|
|
43
|
+
self.assertNotEqual(other[0][1]["job_id"], first[0][1]["job_id"])
|
|
44
|
+
with open(os.path.join(self.staging, other[0][1]["staging"]), encoding="utf-8") as f:
|
|
45
|
+
self.assertIn("bob", f.read())
|
|
40
46
|
with open(path, encoding="utf-8") as f:
|
|
41
47
|
self.assertEqual(f.read(), report)
|
|
42
48
|
|
|
43
|
-
def
|
|
49
|
+
def test_definitive_refusal_cleans_new_source_but_timeout_keeps_retry(self):
|
|
44
50
|
def denied(params):
|
|
45
|
-
raise Error("DELEGATION_DENIED", "The destination is no longer allowed
|
|
46
|
-
|
|
51
|
+
raise Error("DELEGATION_DENIED", "The destination is no longer allowed")
|
|
47
52
|
self.assertEqual(self.save(move=denied).error["code"], "DELEGATION_DENIED")
|
|
53
|
+
self.assertEqual([f for _, _, files in os.walk(self.staging) for f in files], [])
|
|
54
|
+
def timeout(params):
|
|
55
|
+
raise Error("EXECUTOR_TIMEOUT", "The outcome is unknown")
|
|
56
|
+
reply = self.save(move=timeout)
|
|
57
|
+
self.assertTrue(os.path.isfile(os.path.join(self.staging, reply.services[0][1]["staging"])))
|
|
48
58
|
|
|
49
59
|
def test_save_refuses_invalid_params_before_writing(self):
|
|
50
60
|
for params in [None, {"delegation_id": "d1"}, {"delegation_id": "d1", "job_id": "../x"}, {"delegation_id": "d1", "job_id": ""}, {"delegation_id": 1, "job_id": "j"}]:
|
|
@@ -17,7 +17,7 @@ DSM main menu → DSM window (ui/app.js)
|
|
|
17
17
|
|
|
18
18
|
## Requests and long work
|
|
19
19
|
|
|
20
|
-
SDK/App 0.
|
|
20
|
+
SDK/App 0.41.1 defaults to 300-second requests and a 302-second browser wait.
|
|
21
21
|
Explicit `backend.timeout_seconds` and earlier parent deadlines still apply;
|
|
22
22
|
rebuild the App to use the new SDK. For long NAS work, enable the existing jobs
|
|
23
23
|
capability: return admission and the original job ID promptly, execute in the
|
|
@@ -27,7 +27,7 @@ last queued/running state intact. After a lost admission reply, reuse the same
|
|
|
27
27
|
idempotency key and input instead of replaying a mutation with a new key.
|
|
28
28
|
Jobs default to 30 minutes; approved executor limits remain separate. ctl keeps
|
|
29
29
|
its 62-second transport default; use an explicit `--timeout` or an existing
|
|
30
|
-
nonblocking job. See the SDK's [request deadline contract](https://github.com/synopackageland/syno-pkg-land-sdk/blob/v0.
|
|
30
|
+
nonblocking job. See the SDK's [request deadline contract](https://github.com/synopackageland/syno-pkg-land-sdk/blob/v0.41.1/docs/request-deadlines.md).
|
|
31
31
|
|
|
32
32
|
## Quick start
|
|
33
33
|
|
|
@@ -104,8 +104,8 @@ dependencies = [
|
|
|
104
104
|
|
|
105
105
|
[[package]]
|
|
106
106
|
name = "syno-pkg-land-app"
|
|
107
|
-
version = "0.
|
|
108
|
-
source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.
|
|
107
|
+
version = "0.41.1"
|
|
108
|
+
source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.41.1#c2a15fca3f623f6ad25551877ed5097db1df3c25"
|
|
109
109
|
dependencies = [
|
|
110
110
|
"libc",
|
|
111
111
|
"serde",
|
|
@@ -9,7 +9,7 @@ libc = "0.2"
|
|
|
9
9
|
serde = { version = "1", features = ["derive"] }
|
|
10
10
|
serde_json = "1"
|
|
11
11
|
# The SDK version is the tag; `synopkgland check` reads it from Cargo.lock.
|
|
12
|
-
syno-pkg-land-app = { git = "https://github.com/synopackageland/syno-pkg-land-sdk", tag = "v0.
|
|
12
|
+
syno-pkg-land-app = { git = "https://github.com/synopackageland/syno-pkg-land-sdk", tag = "v0.41.1" }
|
|
13
13
|
|
|
14
14
|
[profile.release]
|
|
15
15
|
# A handler panic becomes an "internal" reply; abort would end the App without one.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "app"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"libc",
|
|
10
|
+
"serde",
|
|
11
|
+
"serde_json",
|
|
12
|
+
"sha2",
|
|
13
|
+
"syno-pkg-land-app",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[[package]]
|
|
17
|
+
name = "block-buffer"
|
|
18
|
+
version = "0.10.4"
|
|
19
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
20
|
+
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
|
21
|
+
dependencies = [
|
|
22
|
+
"generic-array",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[[package]]
|
|
26
|
+
name = "cfg-if"
|
|
27
|
+
version = "1.0.5"
|
|
28
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
29
|
+
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
|
30
|
+
|
|
31
|
+
[[package]]
|
|
32
|
+
name = "cpufeatures"
|
|
33
|
+
version = "0.2.17"
|
|
34
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
35
|
+
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
|
36
|
+
dependencies = [
|
|
37
|
+
"libc",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[[package]]
|
|
41
|
+
name = "crypto-common"
|
|
42
|
+
version = "0.1.7"
|
|
43
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
44
|
+
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
|
45
|
+
dependencies = [
|
|
46
|
+
"generic-array",
|
|
47
|
+
"typenum",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[[package]]
|
|
51
|
+
name = "digest"
|
|
52
|
+
version = "0.10.7"
|
|
53
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
54
|
+
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
|
55
|
+
dependencies = [
|
|
56
|
+
"block-buffer",
|
|
57
|
+
"crypto-common",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[[package]]
|
|
61
|
+
name = "generic-array"
|
|
62
|
+
version = "0.14.7"
|
|
63
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
64
|
+
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
|
65
|
+
dependencies = [
|
|
66
|
+
"typenum",
|
|
67
|
+
"version_check",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
[[package]]
|
|
71
|
+
name = "itoa"
|
|
72
|
+
version = "1.0.18"
|
|
73
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
74
|
+
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
75
|
+
|
|
76
|
+
[[package]]
|
|
77
|
+
name = "libc"
|
|
78
|
+
version = "0.2.190"
|
|
79
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
80
|
+
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
|
|
81
|
+
|
|
82
|
+
[[package]]
|
|
83
|
+
name = "memchr"
|
|
84
|
+
version = "2.8.3"
|
|
85
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
86
|
+
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
|
87
|
+
|
|
88
|
+
[[package]]
|
|
89
|
+
name = "proc-macro2"
|
|
90
|
+
version = "1.0.107"
|
|
91
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
92
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
93
|
+
dependencies = [
|
|
94
|
+
"unicode-ident",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
[[package]]
|
|
98
|
+
name = "quote"
|
|
99
|
+
version = "1.0.47"
|
|
100
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
101
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
102
|
+
dependencies = [
|
|
103
|
+
"proc-macro2",
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
[[package]]
|
|
107
|
+
name = "serde"
|
|
108
|
+
version = "1.0.229"
|
|
109
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
110
|
+
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
|
111
|
+
dependencies = [
|
|
112
|
+
"serde_core",
|
|
113
|
+
"serde_derive",
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
[[package]]
|
|
117
|
+
name = "serde_core"
|
|
118
|
+
version = "1.0.229"
|
|
119
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
120
|
+
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
|
121
|
+
dependencies = [
|
|
122
|
+
"serde_derive",
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
[[package]]
|
|
126
|
+
name = "serde_derive"
|
|
127
|
+
version = "1.0.229"
|
|
128
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
129
|
+
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
|
130
|
+
dependencies = [
|
|
131
|
+
"proc-macro2",
|
|
132
|
+
"quote",
|
|
133
|
+
"syn",
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
[[package]]
|
|
137
|
+
name = "serde_json"
|
|
138
|
+
version = "1.0.154"
|
|
139
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
140
|
+
checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6"
|
|
141
|
+
dependencies = [
|
|
142
|
+
"itoa",
|
|
143
|
+
"memchr",
|
|
144
|
+
"serde",
|
|
145
|
+
"serde_core",
|
|
146
|
+
"zmij",
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
[[package]]
|
|
150
|
+
name = "sha2"
|
|
151
|
+
version = "0.10.9"
|
|
152
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
153
|
+
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
|
154
|
+
dependencies = [
|
|
155
|
+
"cfg-if",
|
|
156
|
+
"cpufeatures",
|
|
157
|
+
"digest",
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
[[package]]
|
|
161
|
+
name = "syn"
|
|
162
|
+
version = "3.0.9"
|
|
163
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
164
|
+
checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
|
|
165
|
+
dependencies = [
|
|
166
|
+
"proc-macro2",
|
|
167
|
+
"quote",
|
|
168
|
+
"unicode-ident",
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
[[package]]
|
|
172
|
+
name = "syno-pkg-land-app"
|
|
173
|
+
version = "0.41.1"
|
|
174
|
+
source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.41.1#c2a15fca3f623f6ad25551877ed5097db1df3c25"
|
|
175
|
+
dependencies = [
|
|
176
|
+
"libc",
|
|
177
|
+
"serde",
|
|
178
|
+
"serde_json",
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
[[package]]
|
|
182
|
+
name = "typenum"
|
|
183
|
+
version = "1.20.1"
|
|
184
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
185
|
+
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
|
186
|
+
|
|
187
|
+
[[package]]
|
|
188
|
+
name = "unicode-ident"
|
|
189
|
+
version = "1.0.27"
|
|
190
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
191
|
+
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
|
192
|
+
|
|
193
|
+
[[package]]
|
|
194
|
+
name = "version_check"
|
|
195
|
+
version = "0.9.5"
|
|
196
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
197
|
+
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|
198
|
+
|
|
199
|
+
[[package]]
|
|
200
|
+
name = "zmij"
|
|
201
|
+
version = "1.0.23"
|
|
202
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
203
|
+
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "app"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2024"
|
|
5
|
+
publish = false
|
|
6
|
+
|
|
7
|
+
[dependencies]
|
|
8
|
+
sha2 = "0.10"
|
|
9
|
+
libc = "0.2"
|
|
10
|
+
serde = { version = "1", features = ["derive"] }
|
|
11
|
+
serde_json = "1"
|
|
12
|
+
# The SDK version is the tag; `synopkgland check` reads it from Cargo.lock.
|
|
13
|
+
syno-pkg-land-app = { git = "https://github.com/synopackageland/syno-pkg-land-sdk", tag = "v0.41.1" }
|
|
14
|
+
|
|
15
|
+
[profile.release]
|
|
16
|
+
# A handler panic becomes an "internal" reply; abort would end the App without one.
|
|
17
|
+
panic = "unwind"
|