From 86c11634379ab87238d794f8f9e8bbc991041e4d Mon Sep 17 00:00:00 2001 From: cirakg Date: Tue, 27 Oct 2026 01:08:30 +0100 Subject: fix(import): splitting pasted otpauth:// links runs no character loop OtpAuth.splitUris/firstWord looped over every character in one event, so pasting about 100 links tripped the watchdog (the UI fixture imports Aegis JSON, so it never ran this path). They now use native searches only. New make watchdog case uris_100 (13,576 characters, twice per event) trips on the old code and passes now. fr70: make lint, make test, make watchdog pass. Co-Authored-By: Claude Opus 5.5 --- source/import/OtpAuth.mc | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'source/import') diff --git a/source/import/OtpAuth.mc b/source/import/OtpAuth.mc index cdf0f9c..f5c487b 100644 --- a/source/import/OtpAuth.mc +++ b/source/import/OtpAuth.mc @@ -21,28 +21,35 @@ module OtpAuth { const MIGRATION_PREFIX = "otpauth-migration://"; // The URIs in text, split at every "otpauth://". Text before the first - // one is ignored here; the importer reports it. + // one is ignored here; the importer reports it. Runs in one event, so + // it uses only native searches: a VM loop over every character of 100 + // pasted links tripped the watchdog. function splitUris(text as String) as Array { var uris = [] as Array; - var at = Text.findIgnoreCase(text, PREFIX, 0); - while (at >= 0) { - var next = Text.findIgnoreCase(text, PREFIX, at + PREFIX.length()); - var end = next >= 0 ? next : text.length(); - uris.add(firstWord(text.substring(at, end) as String)); + var lower = text.toLower(); + var at = lower.find(PREFIX); + while (at != null) { + var from = at + PREFIX.length(); + var found = (lower.substring(from, lower.length()) as String).find(PREFIX); + var next = found != null ? from + found : null; + uris.add(firstWord(text.substring(at, next != null ? next : text.length()) as String)); at = next; } return uris; } // Text up to the first whitespace (a pasted URI never contains any). + // Native searches, no loop over the characters (see splitUris). function firstWord(text as String) as String { - var chars = text.toCharArray(); - for (var i = 0; i < chars.size(); i++) { - if (Text.isSpace(chars[i])) { - return text.substring(0, i) as String; + var end = text.length(); + var spaces = [" ", "\t", "\n", "\r"]; + for (var i = 0; i < spaces.size(); i++) { + var found = text.find(spaces[i]); + if (found != null && found < end) { + end = found; } } - return text; + return end == text.length() ? text : text.substring(0, end) as String; } // One URI as an import item (entry, problem or skip). -- cgit v1.2.3