feat(privacy): the instance's side of private studysets (ADR 0019)
- `content_key`, a synced table in the person's space, keeps their data keys sealed to their account (a private studyset's, their personal one); `learning_path_answer` gains `keyId` and `nonce` for answers in private studysets. Additive only, on the server and the device. - Publishing refuses a private studyset, and a tree holding a private row (`PublishRefusal.private`); a private studyset elsewhere no longer breaks publishing a readable one. Encrypted tags are named as the device names them (`tagNames`): a name for a tag that isn't the person's, or an encrypted tag of the release without one, refuses it (`tagNamesMismatch`); a readable tag keeps its own name. - The connector leaves private studysets out and says how many there are. - The learner count reads no payload any more: Count me is kept by the instance (`counted_learner`) and the device reports which publications its copies come from (`learning_copy`, accepted only while counted, each report replacing the last); only the reporter's own studysets count. Deleting a person deletes both. - An upload says whether its file is encrypted: only a readable one over 20 MB is checked to be a PDF, and an encrypted one may be 4 KiB larger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
074d05ab4e
commit
a1c5ac3f86
1 changed files with 35261 additions and 198 deletions
|
|
@ -38,6 +38,8 @@ import 'package:halkyon_learn_server/src/generated/discussion/discussion_target.
|
|||
as _ike2gc23;
|
||||
import 'package:halkyon_learn_server/src/generated/discussion/discussion_view.dart'
|
||||
as _ikk5e562;
|
||||
import 'package:halkyon_learn_server/src/generated/explore/copy_report.dart'
|
||||
as _ipludy4j;
|
||||
import 'package:halkyon_learn_server/src/generated/explore/explore_entry.dart'
|
||||
as _iscq690j;
|
||||
import 'package:halkyon_learn_server/src/generated/explore/explore_query.dart'
|
||||
|
|
@ -205,6 +207,8 @@ class TestEndpoints {
|
|||
|
||||
late final _ExploreEndpoint explore;
|
||||
|
||||
late final _LearningCountEndpoint learningCount;
|
||||
|
||||
late final _FeedbackEndpoint feedback;
|
||||
|
||||
late final _InboxEndpoint inbox;
|
||||
|
|
@ -249,6 +253,10 @@ class _InternalTestEndpoints extends TestEndpoints
|
|||
endpoints,
|
||||
serializationManager,
|
||||
);
|
||||
learningCount = _LearningCountEndpoint(
|
||||
endpoints,
|
||||
serializationManager,
|
||||
);
|
||||
feedback = _FeedbackEndpoint(
|
||||
endpoints,
|
||||
serializationManager,
|
||||
|
|
@ -291,8 +299,9 @@ class _AssetEndpoint {
|
|||
_ida.Future<String?> startUpload(
|
||||
_ist.TestSessionBuilder sessionBuilder,
|
||||
String sha256,
|
||||
int byteSize,
|
||||
) async {
|
||||
int byteSize, {
|
||||
bool? encrypted,
|
||||
}) async {
|
||||
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
|
||||
var _localUniqueSession =
|
||||
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild(
|
||||
|
|
@ -307,6 +316,7 @@ class _AssetEndpoint {
|
|||
parameters: _ist.testObjectToJson({
|
||||
'sha256': sha256,
|
||||
'byteSize': byteSize,
|
||||
'encrypted': encrypted,
|
||||
}),
|
||||
serializationManager: _serializationManager,
|
||||
);
|
||||
|
|
@ -325,8 +335,9 @@ class _AssetEndpoint {
|
|||
|
||||
_ida.Future<bool> finishUpload(
|
||||
_ist.TestSessionBuilder sessionBuilder,
|
||||
String sha256,
|
||||
) async {
|
||||
String sha256, {
|
||||
bool? encrypted,
|
||||
}) async {
|
||||
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
|
||||
var _localUniqueSession =
|
||||
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild(
|
||||
|
|
@ -338,7 +349,10 @@ class _AssetEndpoint {
|
|||
createSessionCallback: (_) => _localUniqueSession,
|
||||
endpointPath: 'asset',
|
||||
methodName: 'finishUpload',
|
||||
parameters: _ist.testObjectToJson({'sha256': sha256}),
|
||||
parameters: _ist.testObjectToJson({
|
||||
'sha256': sha256,
|
||||
'encrypted': encrypted,
|
||||
}),
|
||||
serializationManager: _serializationManager,
|
||||
);
|
||||
var _localReturnValue =
|
||||
|
|
@ -1535,6 +1549,107 @@ class _ExploreEndpoint {
|
|||
}
|
||||
}
|
||||
|
||||
class _LearningCountEndpoint {
|
||||
_LearningCountEndpoint(
|
||||
this._endpointDispatch,
|
||||
this._serializationManager,
|
||||
);
|
||||
|
||||
final _is.EndpointDispatch _endpointDispatch;
|
||||
|
||||
final _is.SerializationManager _serializationManager;
|
||||
|
||||
_ida.Future<bool> counted(_ist.TestSessionBuilder sessionBuilder) async {
|
||||
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
|
||||
var _localUniqueSession =
|
||||
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild(
|
||||
endpoint: 'learningCount',
|
||||
method: 'counted',
|
||||
);
|
||||
try {
|
||||
var _localCallContext = await _endpointDispatch.getMethodCallContext(
|
||||
createSessionCallback: (_) => _localUniqueSession,
|
||||
endpointPath: 'learningCount',
|
||||
methodName: 'counted',
|
||||
parameters: _ist.testObjectToJson({}),
|
||||
serializationManager: _serializationManager,
|
||||
);
|
||||
var _localReturnValue =
|
||||
await (_localCallContext.method.call(
|
||||
_localUniqueSession,
|
||||
_localCallContext.arguments,
|
||||
)
|
||||
as _ida.Future<bool>);
|
||||
return _localReturnValue;
|
||||
} finally {
|
||||
await _localUniqueSession.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_ida.Future<void> setCounted(
|
||||
_ist.TestSessionBuilder sessionBuilder,
|
||||
bool counted,
|
||||
) async {
|
||||
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
|
||||
var _localUniqueSession =
|
||||
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild(
|
||||
endpoint: 'learningCount',
|
||||
method: 'setCounted',
|
||||
);
|
||||
try {
|
||||
var _localCallContext = await _endpointDispatch.getMethodCallContext(
|
||||
createSessionCallback: (_) => _localUniqueSession,
|
||||
endpointPath: 'learningCount',
|
||||
methodName: 'setCounted',
|
||||
parameters: _ist.testObjectToJson({'counted': counted}),
|
||||
serializationManager: _serializationManager,
|
||||
);
|
||||
var _localReturnValue =
|
||||
await (_localCallContext.method.call(
|
||||
_localUniqueSession,
|
||||
_localCallContext.arguments,
|
||||
)
|
||||
as _ida.Future<void>);
|
||||
return _localReturnValue;
|
||||
} finally {
|
||||
await _localUniqueSession.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_ida.Future<bool> reportCopies(
|
||||
_ist.TestSessionBuilder sessionBuilder,
|
||||
List<_ipludy4j.CopyReport> copies,
|
||||
) async {
|
||||
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
|
||||
var _localUniqueSession =
|
||||
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild(
|
||||
endpoint: 'learningCount',
|
||||
method: 'reportCopies',
|
||||
);
|
||||
try {
|
||||
var _localCallContext = await _endpointDispatch.getMethodCallContext(
|
||||
createSessionCallback: (_) => _localUniqueSession,
|
||||
endpointPath: 'learningCount',
|
||||
methodName: 'reportCopies',
|
||||
parameters: _ist.testObjectToJson({'copies': copies}),
|
||||
serializationManager: _serializationManager,
|
||||
);
|
||||
var _localReturnValue =
|
||||
await (_localCallContext.method.call(
|
||||
_localUniqueSession,
|
||||
_localCallContext.arguments,
|
||||
)
|
||||
as _ida.Future<bool>);
|
||||
return _localReturnValue;
|
||||
} finally {
|
||||
await _localUniqueSession.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _FeedbackEndpoint {
|
||||
_FeedbackEndpoint(
|
||||
this._endpointDispatch,
|
||||
|
|
@ -1922,6 +2037,7 @@ class _PublishEndpoint {
|
|||
String slug,
|
||||
String notes, {
|
||||
String? description,
|
||||
Map<String, String>? tagNames,
|
||||
}) async {
|
||||
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
|
||||
var _localUniqueSession =
|
||||
|
|
@ -1939,6 +2055,7 @@ class _PublishEndpoint {
|
|||
'slug': slug,
|
||||
'notes': notes,
|
||||
'description': description,
|
||||
'tagNames': tagNames,
|
||||
}),
|
||||
serializationManager: _serializationManager,
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue