Skip to content

Own LINE crypto by session and login attempt - #253

Merged
iFixRobots merged 7 commits into
mainfrom
iFixRobots/own-line-crypto-runtimes
Oct 6, 2026
Merged

iFixRobots merged 7 commits into
mainfrom
iFixRobots/own-line-crypto-runtimes

Conversation

@iFixRobots

@iFixRobots iFixRobots commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

LINE managers currently share one process-global crypto heap. Replacing or deleting a session leaves its keys and channels in that heap, and overlapping logins overwrite the same login/storage state. Recovering an authoritative allocator abort also leaves stale handles usable.

Give each session and login attempt its own Runner. Carry the attempt through PIN verification, confirmation and key export, then close it on completion/cancellation. Disconnect closes the session owner after draining workers and recovery. Closed or aborted owners reject native and cached-Go operations without invoking destructors on a damaged heap.

Also reuse identical own-key imports, preserve distinct historical keys only for the verified same account, propagate aborts after partially successful batch loads, and reject retired/canceled clients before initial and retry RPCs. Terminal crypto failures cannot downgrade group sends to plaintext. Generated registration keys have tracked temporary ownership and are released after wrapping, before the registration RPC.

Requires canonical maunium.net/go/mautrix v0.31.1-0.20261005174338-57e1ea5dd74d, containing the merged upstream cancellation-admission fix. No framework fork or replacement is used.

Rebased on current LINE main, retaining #256's bounded group-key eviction and locking. Eviction now follows the same terminal-owner gate and stops at the first native destruction failure instead of continuing cleanup on a possibly damaged heap.

Follow-up #254 keeps full registration generation/wrapping on a disposable heap. Megabridge #39 adopts the final source stack.

Base automatically changed from iFixRobots/fix-native-group-key-ownership to main October 5, 2026 16:41
@indent
indent Bot force-pushed the iFixRobots/own-line-crypto-runtimes branch from db96479 to 9a9abc6 Compare October 5, 2026 18:00
@indent
indent Bot marked this pull request as ready for review October 5, 2026 18:02
@indent

indent Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Issues

All clear! No issues remaining. 🎉

3 issues already resolved
  • After Disconnect closes lc.E2EE, decryptMessageBody in handle_message.go sees gen.ErrRunnerClosed, not ltsm.ErrAbort. It then calls MyKeyIDs, which also fails, and wraps the result as ErrMissingOwnPrivateKey and calls markMissingE2EEKey. That sets ForceFullE2EELogin, clears Certificate on the shared login metadata and sends BadCredentials, so a replacement client inherits a poisoned login. (fixed by commit c21bb56)
    Found by Indent Review Agent
  • fetchLoginKeys now returns exportLoginE2EEKeys errors and finishLogin fails immediately. Previously the error was logged and shouldPreserveExistingE2EEKeys kept the existing keys. A transient GetEncryptedIdentityV3 or unwrap failure now fails a reconnect after the user has already confirmed on their phone. (fixed by commit 0a69552)
    Found by Indent Review Agent
  • The new keep-existing-keys fallback in tryLogin requires lc.E2EE != nil, but during Connect startup (no access token or expired token via ensureValidToken) tryLogin runs before e2ee.NewManager(), so lc.E2EE is nil. A transient key export or unwrap error there still returns "refresh re-login E2EE keys", discards the freshly issued tokens and reports BadCredentials "line-login-failed". (fixed by commit 9377b1a)
    Found by Indent Review Agent

CI Checks

All CI checks passed on 9377b1a.

Review agents

Select any unchecked box below to run or rerun that agent.

Passed (1)
  • Indent Review Agent · 9377b1a fixes the startup tryLogin fallback; no new bugs found.
Full results

Indent Review Agent

  • Summary: 9377b1a fixes the startup tryLogin fallback; no new bugs found.
  • Last ran on commit: 9377b1af
  • Latest result
    {
      "summary": "9377b1af fixes the startup tryLogin fallback; no new bugs found.",
      "findings": []
    }

Keep the established manual reconnect fallback for a verified same account with stored keys. Cancellation, deadlines, terminal crypto errors, forced full verification and account mismatches still reject completion.
…h errors

Preserve staged token publication for the verified same account when existing key metadata is reusable and the active owner remains usable. Failed fresh-key validation does not publish partial key metadata. Cancellation, retirement, forced verification and terminal crypto failures still stop recovery.
@beeper beeper deleted a comment from indent Bot Oct 5, 2026
@beeper beeper deleted a comment from indent Bot Oct 5, 2026
@beeper beeper deleted a comment from indent Bot Oct 5, 2026
@beeper beeper deleted a comment from indent Bot Oct 5, 2026
@beeper beeper deleted a comment from indent Bot Oct 5, 2026
@beeper beeper deleted a comment from indent Bot Oct 5, 2026
Comment thread pkg/connector/client.go Outdated
if res.Certificate != "" {
meta.Certificate = res.Certificate
if keyErr != nil {
if isTerminalCryptoError(keyErr) || errors.Is(keyErr, context.Canceled) || errors.Is(keyErr, context.DeadlineExceeded) || res.Mid != string(lc.UserLogin.ID) || res.Mid != meta.Mid || !shouldPreserveExistingE2EEKeys(false, meta) || lc.E2EE == nil {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if isTerminalCryptoError(keyErr) || errors.Is(keyErr, context.Canceled) || errors.Is(keyErr, context.DeadlineExceeded) || res.Mid != string(lc.UserLogin.ID) || res.Mid != meta.Mid || !shouldPreserveExistingE2EEKeys(false, meta) || lc.E2EE == nil {
if isTerminalCryptoError(keyErr) || errors.Is(keyErr, context.Canceled) || errors.Is(keyErr, context.DeadlineExceeded) || res.Mid != string(lc.UserLogin.ID) || res.Mid != meta.Mid || !shouldPreserveExistingE2EEKeys(false, meta) {

Comment thread pkg/connector/client.go Outdated
if err := lc.admitRecoveredLogin(ctx, res); err != nil {
return err
}
if keyErr != nil {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if keyErr != nil {
if keyErr != nil && lc.E2EE != nil {

Comment thread pkg/connector/client.go Outdated
line.InvalidateOBSTokenCache()
if mgr != nil {
if err := mgr.SaveSecureDataToFile(loginSecureDataID(&staged, string(lc.UserLogin.ID)), map[string]any{"exportedKeyMap": exported}); err != nil {
return fmt.Errorf("save recovered E2EE secure data: %w", err)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a failure to save the secure data file should not fail the login and surface as badcredentials.
A warning should be logged instead with the return being nil

Comment thread pkg/connector/client.go Outdated
} else if ctx.Err() != nil {
return ctx.Err()
} else if lc.isLoggedOut(err) || errors.Is(err, errLineSessionInvalidated) {
} else if lc.isLoggedOut(err) || errors.Is(err, errLineSessionInvalidated) || errors.Is(err, errLineClientSuperseded) || errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} else if lc.isLoggedOut(err) || errors.Is(err, errLineSessionInvalidated) || errors.Is(err, errLineClientSuperseded) || errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
} else if lc.isLoggedOut(err) || errors.Is(err, errLineSessionInvalidated) || errors.Is(err, errLineClientSuperseded) || errors.Is(err, context.Canceled) {

a refresh timeout would fail here and skip the relogin its supposed to follow

Comment thread pkg/connector/connector.go Outdated
if shouldPreserveExistingE2EEKeys(exportedKeys, ll.ExistingMetadata) {
loginManager, err := ll.fetchLoginKeys(res, meta, client)
if err != nil {
if isTerminalCryptoError(err) || errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) || !sameAccount || !shouldPreserveExistingE2EEKeys(false, ll.ExistingMetadata) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same timeout issue as previous comment

Comment thread pkg/connector/client.go
if err := mgr.LoadMyKeyFromExportedMap(exported); err != nil {
keyErr = fmt.Errorf("validate recovered E2EE keys: %w", err)
} else {
applyExportedLoginE2EEKeys(&staged, res, exported)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
applyExportedLoginE2EEKeys(&staged, res, exported)
lc.applyRefreshedLoginE2EEKeys(&staged, res, exported)

case <-done:
return nil, context.Canceled
case <-ctx.Done():
ll.Cancel()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A client or HTTP timeout shorter than PIN entry permanently cancels the login. Is that intended?

Distinguish individual HTTP timeouts from expired caller or login-attempt contexts. Allow stored-key fallback during startup before an E2EE manager exists. Reset missing-key notification state only after fresh keys, database metadata and live tokens are published successfully. Keep post-publication secure-file failures warning-only.
@iFixRobots
iFixRobots requested a review from highesttt October 5, 2026 21:48
@iFixRobots
iFixRobots merged commit eeb41a8 into main Oct 6, 2026
9 checks passed
@iFixRobots
iFixRobots deleted the iFixRobots/own-line-crypto-runtimes branch October 6, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants