Ingo Schiermeyer

162 papers A* 1A 1B 4C 2Journal 151Unranked 1
YearRankTypeTitle / Venue / Authors
2026 J jnl
Discuss. Math. Graph Theory
Meng Ji, Yaping Mao, Ingo Schiermeyer
2026 J jnl
Discret. Math.
Nadzieja Hodur, Monika Pilsniak, Magdalena Prorok, Ingo Schiermeyer
2024 J jnl
Graphs Comb.
Zhiwei Guo, Christoph Brause, Maximilian Geißer, Ingo Schiermeyer
2024 J jnl
Discret. Appl. Math.
Zhiqiang Ma, Yaping Mao, Ingo Schiermeyer, Meiqin Wei
2024 J jnl
Graphs Comb.
Ping Li, Yaping Mao, Ingo Schiermeyer, Yifan Yao
2024 J jnl
Appl. Math. Comput.
Trung Duy Doan, Thi Thanh Chau Do, Ingo Schiermeyer
2024 J jnl
Appl. Math. Comput.
Trung Duy Doan, Thi Thanh Chau Do, Pham Hoang Ha, Ngoc Diep Pham, Ingo Schiermeyer
2024 J jnl
Discret. Appl. Math.
Christoph Brause, Trung Duy Doan, Ingo Schiermeyer
2023 J jnl
Discret. Math.
Yaping Mao, Zhao Wang, Colton Magnant, Ingo Schiermeyer
2023 J jnl
Graphs Comb.
Christoph Brause, Stanislav Jendrol', Ingo Schiermeyer
2022 J jnl
Discret. Math.
Christoph Brause, Trung Duy Doan, Premysl Holub, Adam Kabela, Zdenek Ryjácek, Ingo Schiermeyer, Petr Vrána
2022 J jnl
J. Graph Theory
Colton Magnant, Ingo Schiermeyer
2022 J jnl
Discret. Appl. Math.
Christoph Brause, Maximilian Geißer, Ingo Schiermeyer
2022 J jnl
Graphs Comb.
Yaping Mao, Zhao Wang, Colton Magnant, Ingo Schiermeyer
2022 J jnl
Graphs Comb.
Trung Duy Doan, Pham Hoang Ha, Ingo Schiermeyer
2022 J jnl
Discret. Appl. Math.
Trung Duy Doan, Ingo Schiermeyer
2021 J jnl
Graphs Comb.
Trung Duy Doan, Ingo Schiermeyer
2021 J jnl
Discuss. Math. Graph Theory
Trung Duy Doan, Ingo Schiermeyer
2021 J jnl
Graphs Comb.
Christoph Brause, Stanislav Jendrol', Ingo Schiermeyer
2021 J jnl
Discuss. Math. Graph Theory
Trung Duy Doan, Ingo Schiermeyer
2020 J jnl
J. Graph Theory
Henry Liu, Colton Magnant, Akira Saito, Ingo Schiermeyer, Yongtang Shi
2020 J jnl
Discret. Appl. Math.
Yaping Mao, Zhao Wang, Colton Magnant, Ingo Schiermeyer
2019 J jnl
Discret. Appl. Math.
Ingo Schiermeyer
2019 J jnl
Discret. Math.
Christoph Brause, Premysl Holub, Adam Kabela, Zdenek Ryjácek, Ingo Schiermeyer, Petr Vrána
2019 J jnl
Discret. Appl. Math.
Christoph Brause, Bert Randerath, Ingo Schiermeyer, Elkin Vumar
2019 J jnl
Graphs Comb.
Ingo Schiermeyer, Bert Randerath
2018 J jnl
Graphs Comb.
Hong Chang, Trung Duy Doan, Zhong Huang, Stanislav Jendrol', Xueliang Li, Ingo Schiermeyer
2018 J jnl
Discret. Math.
Christoph Brause, Stanislav Jendrol', Ingo Schiermeyer
2018 J jnl
Discret. Appl. Math.
Christoph Brause, Michael A. Henning, Kenta Ozeki, Ingo Schiermeyer, Elkin Vumar
2017 J jnl
Discret. Math.
Christoph Brause, Dieter Rautenbach, Ingo Schiermeyer
2017 J jnl
Graphs Comb.
Christoph Brause, Trung Duy Doan, Ingo Schiermeyer
2017 J jnl
Discuss. Math. Graph Theory
Christoph Brause, Ngoc Chi Lê, Ingo Schiermeyer
2017 J jnl
Discret. Math.
Susan A. van Aardt, Christoph Brause, Alewyn P. Burger, Marietjie Frick, Arnfried Kemnitz, Ingo Schiermeyer
2016 J jnl
Discret. Appl. Math.
Christoph Brause, Bert Randerath, Dieter Rautenbach, Ingo Schiermeyer
2016 J jnl
Discret. Math.
Premysl Holub, Zdenek Ryjácek, Ingo Schiermeyer, Petr Vrána
2016 J jnl
Discret. Math.
Ingo Schiermeyer
2016 J jnl
Discuss. Math. Graph Theory
Rafal Kalinowski, Monika Pilsniak, Ingo Schiermeyer, Mariusz Wozniak
2016 J jnl
Discret. Math.
Christoph Brause, Ingo Schiermeyer
2016 J jnl
Graphs Comb.
Binlong Li, Ingo Schiermeyer
2016 J jnl
Graphs Comb.
Mirko Hornák, Stanislav Jendrol', Ingo Schiermeyer
2016 J jnl
Electron. Notes Discret. Math.
Christoph Brause, Trung Duy Doan, Ingo Schiermeyer
2016 J jnl
Discret. Math.
Mirko Hornák, Stanislav Jendrol', Ingo Schiermeyer
2016 J jnl
Electron. Notes Discret. Math.
Christoph Brause, Trung Duy Doan, Ingo Schiermeyer
2016 J jnl
Electron. Notes Discret. Math.
Christoph Brause, Trung Duy Doan, Ingo Schiermeyer
2016 J jnl
Discret. Appl. Math.
Arnfried Kemnitz, Ingo Schiermeyer
2015 J jnl
Electron. Notes Discret. Math.
Christoph Brause, Ingo Schiermeyer, Premysl Holub, Zdenek Ryjácek, Petr Vrána, Rastislav Krivos-Bellus
2015 J jnl
Discuss. Math. Graph Theory
Christoph Brause, Ngoc Chi Lê, Ingo Schiermeyer
2015 J jnl
Discuss. Math. Graph Theory
Xueliang Li, Ingo Schiermeyer, Kang Yang, Yan Zhao
2015 J jnl
Discuss. Math. Graph Theory
Xueliang Li, Ingo Schiermeyer, Kang Yang, Yan Zhao
2015 J jnl
Graphs Comb.
Susan A. van Aardt, Alewyn P. Burger, Marietjie Frick, Arnfried Kemnitz, Ingo Schiermeyer
2015 J jnl
Discret. Math.
Ngoc Chi Lê, Christoph Brause, Ingo Schiermeyer
2015 J jnl
Discret. Math.
Premysl Holub, Zdenek Ryjácek, Ingo Schiermeyer
2015 J jnl
J. Graph Theory
Mirko Hornák, Stanislav Jendrol', Ingo Schiermeyer, Roman Soták
2015 J jnl
Graphs Comb.
Ingo Schiermeyer, Roman Soták
2015 J jnl
Discret. Math.
Premysl Holub, Zdenek Ryjácek, Ingo Schiermeyer, Petr Vrána
2015 J jnl
Electron. Notes Discret. Math.
Ngoc Chi Lê, Christoph Brause, Ingo Schiermeyer
2015 J jnl
Discret. Math.
Christoph Brause, Ngoc Chi Lê, Ingo Schiermeyer
2014 J jnl
Discret. Appl. Math.
Paul Dorbec, Ingo Schiermeyer, Elzbieta Sidorowicz, Éric Sopena
2014 J jnl
Discret. Math.
Stanislav Jendrol', Ingo Schiermeyer, Jianhua Tu
2013 J jnl
Discuss. Math. Graph Theory
Mirko Hornák, Stanislav Jendrol', Ingo Schiermeyer
2013 J jnl
Discret. Appl. Math.
Ingo Schiermeyer
2013 J jnl
Ars Math. Contemp.
Ingo Schiermeyer
2013 J jnl
Discret. Appl. Math.
Ingo Schiermeyer
2013 J jnl
Discuss. Math. Graph Theory
Arnfried Kemnitz, Jakub Przybylo, Ingo Schiermeyer, Mariusz Wozniak
2013 J jnl
Discuss. Math. Graph Theory
Xueliang Li, Mengmeng Liu, Ingo Schiermeyer
2013 J jnl
Discret. Math.
Jan Ekstein, Premysl Holub, Tomás Kaiser, Maria Koch, Stephan Matos Camacho, Zdenek Ryjácek, Ingo Schiermeyer
2012 J jnl
Discret. Math.
Stanislav Jendrol', Tomás Kaiser, Zdenek Ryjácek, Ingo Schiermeyer
2012 J jnl
J. Graph Theory
Jochen Harant, Arnfried Kemnitz, Akira Saito, Ingo Schiermeyer
2012 J jnl
Graphs Comb.
Mirko Hornák, Antoni Marczyk, Ingo Schiermeyer, Mariusz Wozniak
2012 J jnl
Discret. Math.
Arnfried Kemnitz, Ingo Schiermeyer
2011 J jnl
Electron. J. Comb.
Michael A. Henning, Ingo Schiermeyer, Anders Yeo
2011 J jnl
Comb.
Jun Fujisawa, Shinya Fujita, Michael D. Plummer, Akira Saito, Ingo Schiermeyer
2011 J jnl
Electron. Notes Discret. Math.
Maria Koch, Stephan Matos Camacho, Ingo Schiermeyer
2011 J jnl
Discuss. Math. Graph Theory
Ingo Schiermeyer
2011 J jnl
Discuss. Math. Graph Theory
Jun Fujisawa, Akira Saito, Ingo Schiermeyer
2011 J jnl
Discuss. Math. Graph Theory
Arnfried Kemnitz, Ingo Schiermeyer
2011 J jnl
Inf. Process. Lett.
Ján Katrenic, Ingo Schiermeyer
2011 J jnl
Theor. Comput. Sci.
Frantisek Kardos, Ján Katrenic, Ingo Schiermeyer
2010 J jnl
Discret. Math.
Stephan Matos Camacho, Ingo Schiermeyer, Zsolt Tuza
2010 J jnl
J. Graph Theory
Christian Löwenstein, Dieter Rautenbach, Ingo Schiermeyer
2010 J jnl
Discret. Appl. Math.
Bert Randerath, Ingo Schiermeyer
2010 J jnl
Discret. Math.
Jochen Harant, Dieter Rautenbach, Peter Recht, Ingo Schiermeyer, Eva-Maria Sprengel
2010 C conf
CTW
Ingo Schiermeyer
2010 J jnl
Electron. J. Comb.
Sarah Artmann, Frank Göring, Jochen Harant, Dieter Rautenbach, Ingo Schiermeyer
2010 J jnl
Discret. Math.
Anja Kohl, Ingo Schiermeyer
2010 J jnl
Graphs Comb.
Ingo Schiermeyer, Martin Sonntag, Hanns-Martin Teichert
2009 J jnl
Electron. J. Comb.
Shinya Fujita, Atsushi Kaneko, Ingo Schiermeyer, Kazuhiro Suzuki
2009 J jnl
Discret. Math.
Stephan Matos Camacho, Ingo Schiermeyer
2009 J jnl
Discuss. Math. Graph Theory
Frank Göring, Jochen Harant, Dieter Rautenbach, Ingo Schiermeyer
2009 J jnl
Discret. Math.
Ralph J. Faudree, Linda M. Lesniak, Ingo Schiermeyer
2009 C conf
IWOCA
Ingo Schiermeyer
2008 J jnl
Discret. Appl. Math.
Ingo Schiermeyer
2008 J jnl
J. Graph Theory
Guantao Chen, Ralph J. Faudree, Xuechao Li, Ingo Schiermeyer
2008 J jnl
Discret. Math.
Jochen Harant, Michael A. Henning, Dieter Rautenbach, Ingo Schiermeyer
2007 J jnl
Discuss. Math. Graph Theory
Ingo Schiermeyer
2007 J jnl
Discuss. Math. Graph Theory
Guantao Chen, Ronald J. Gould, Ken-ichi Kawarabayashi, Katsuhiro Ota, Akira Saito, Ingo Schiermeyer
2007 J jnl
Discret. Math.
Ralph J. Faudree, Richard H. Schelp, Akira Saito, Ingo Schiermeyer
2007 J jnl
Discret. Math.
Yoshimi Egawa, Hikoe Enomoto, Stanislav Jendrol', Katsuhiro Ota, Ingo Schiermeyer
2007 J jnl
Discuss. Math. Graph Theory
Ingo Schiermeyer, Mariusz Wozniak
2007 J jnl
Theor. Comput. Sci.
Van Bang Le, Bert Randerath, Ingo Schiermeyer
2007 J jnl
Graphs Comb.
Maria Axenovich, Heiko Harborth, Arnfried Kemnitz, Meinhard Möller, Ingo Schiermeyer
2006 J jnl
Discuss. Math. Graph Theory
Jochen Harant, Ingo Schiermeyer
2006 J jnl
Discuss. Math. Graph Theory
Evelyne Flandrin, Hao Li, Antoni Marczyk, Ingo Schiermeyer, Mariusz Wozniak
2006 J jnl
Graphs Comb.
Dieter Rautenbach, Ingo Schiermeyer
2006 J jnl
Electron. Notes Discret. Math.
Ingo Schiermeyer
2005 J jnl
Electron. J. Comb.
Marietjie Frick, Ingo Schiermeyer
2005 J jnl
Electron. J. Comb.
Mieczyslaw Borowiecki, Ingo Schiermeyer, Elzbieta Sidorowicz
2005 J jnl
Discuss. Math. Graph Theory
Ingo Schiermeyer
2004 J jnl
Discret. Appl. Math.
Bert Randerath, Ingo Schiermeyer
2004 J jnl
Discret. Math.
Peter Mihók, Ingo Schiermeyer
2004 J jnl
Discret. Math.
Ingo Schiermeyer
2004 J jnl
Graphs Comb.
Bert Randerath, Ingo Schiermeyer
2003 J jnl
Graphs Comb.
Ahmed Ainouche, Ingo Schiermeyer
2003 J jnl
J. Graph Theory
Ingo Schiermeyer
2003 J jnl
J. Graph Theory
Ralph J. Faudree, Ronald J. Gould, Alexandr V. Kostochka, Linda M. Lesniak, Ingo Schiermeyer, Akira Saito
2003 J jnl
Discuss. Math. Graph Theory
Ralph J. Faudree, Annette Schelten, Ingo Schiermeyer
2003 J jnl
J. Graph Theory
Yoshimi Egawa, Hikoe Enomoto, Ralph J. Faudree, Hao Li, Ingo Schiermeyer
2002 J jnl
Australas. J Comb.
Bert Randerath, Ingo Schiermeyer
2002 J jnl
Discret. Math.
Jochen Harant, Zdenek Ryjácek, Ingo Schiermeyer
2002 J jnl
Graphs Comb.
Ingo Schiermeyer, Meike Tewes
2002 J jnl
Discuss. Math. Graph Theory
Jochen Harant, Ingo Schiermeyer, Margit Voigt
2002 J jnl
Discret. Math.
Bert Randerath, Ingo Schiermeyer, Meike Tewes
2002 J jnl
Discret. Appl. Math.
Bert Randerath, Ingo Schiermeyer, Meike Tewes, Lutz Volkmann
2001 J jnl
Electron. Notes Discret. Math.
Bert Randerath, Ingo Schiermeyer
2001 J jnl
Discuss. Math. Graph Theory
Bert Randerath, Ingo Schiermeyer
2001 J jnl
Comb.
Stanislav Jendrol', Ingo Schiermeyer
2001 J jnl
Discret. Math.
Jochen Harant, Ingo Schiermeyer
2001 J jnl
Discuss. Math. Graph Theory
Ingo Schiermeyer
2001 J jnl
J. Graph Theory
Jochen Harant, Margit Voigt, Stanislav Jendrol', Bert Randerath, Zdenek Ryjácek, Ingo Schiermeyer
2000 J jnl
Graphs Comb.
Hajo Broersma, Zdenek Ryjácek, Ingo Schiermeyer
2000 J jnl
Discret. Math.
Ingo Schiermeyer, Zsolt Tuza, Margit Voigt
1999 J jnl
Electron. Notes Discret. Math.
Annette Schelten, Ingo Schiermeyer, Ralph J. Faudree
1999 A* conf
SODA
Ingo Schiermeyer, Bert Randerath
1999 J jnl
Discret. Math.
Jan Brousek, Zdenek Ryjácek, Ingo Schiermeyer
1999 ch.
Angewandte Mathematik, insbesondere Informatik
Ingo Schiermeyer
1999 J jnl
Discret. Math.
Bert Randerath, Ingo Schiermeyer, Hong Wang
1999 J jnl
Electron. Notes Discret. Math.
Bert Randerath, Lutz Volkmann, Ingo Schiermeyer, Meike Tewes
1998 J jnl
Discret. Math.
Zdenek Ryjácek, Ingo Schiermeyer
1998 J jnl
Discret. Math.
Thomas Böhme, Jochen Harant, Anja Pruchnewski, Ingo Schiermeyer
1998 conf
APPROX
Ingo Schiermeyer
1998 J jnl
Discret. Math.
Annette Schelten, Ingo Schiermeyer
1997 J jnl
Discret. Math.
Haitze J. Broersma, Zdenek Ryjácek, Ingo Schiermeyer
1997 J jnl
Ars Comb.
Ralph J. Faudree, Zdenek Ryjácek, Ingo Schiermeyer
1997 J jnl
Discuss. Math. Graph Theory
Jan Kratochvíl, Ingo Schiermeyer
1997 J jnl
Discret. Appl. Math.
Annette Schelten, Ingo Schiermeyer
1997 J jnl
Discret. Appl. Math.
Uwe Schelten, Ingo Schiermeyer
1996 J jnl
J. Graph Theory
Haitze J. Broersma, Zdenek Ryjácek, Ingo Schiermeyer
1995 B conf
WG
Ingo Schiermeyer
1995 J jnl
J. Graph Theory
Ahmed Ainouche, Ingo Schiermeyer
1995 J jnl
Discret. Math.
Zdenek Ryjácek, Ingo Schiermeyer
1995 J jnl
Discuss. Math. Graph Theory
Ingo Schiermeyer
1995 J jnl
Discuss. Math. Graph Theory
Zdenek Ryjácek, Ingo Schiermeyer
1994 J jnl
Discret. Math.
Haitze J. Broersma, Ingo Schiermeyer
1994 J jnl
SIAM J. Discret. Math.
Peter Dankelmann, Thomas Niessen, Ingo Schiermeyer
1994 A conf
ESA
Ingo Schiermeyer
1994 J jnl
Discret. Appl. Math.
Hajo Broersma, Ingo Schiermeyer
1994 J jnl
Discret. Math.
Ingo Schiermeyer
1993 J jnl
Discret. Math.
Ingo Schiermeyer
1993 B conf
WG
Ingo Schiermeyer
1992 B conf
CSL
Ingo Schiermeyer
1989 B conf
WG
Ingo Schiermeyer
1988
Ingo Schiermeyer
redb/extractors/js_extractors/js_strings.py
← Index redb/extractors/js_extractors/js_strings.py python
import base64
import bisect
import inspect
import re
from datetime import datetime, timezone
from typing import Any

from redb.extractors.enum import Tag
from redb.extractors.js_extractor import JSExtractor
from redb.extractors.js_extractors.js_patterns import STRING_PATTERNS, line_offsets

# Local aliases for the compiled patterns this extractor uses. Defined and
# compiled exactly once in js_patterns.STRING_PATTERNS.
_HEX_STRING_RE = STRING_PATTERNS["hex_escape_seq"]
_UNICODE_STRING_RE = STRING_PATTERNS["unicode_escape_seq"]
_CHARCODE_RE = STRING_PATTERNS["charcode_call"]
_BASE64_STRING_RE = STRING_PATTERNS["base64_quoted"]
_CONCAT_STRING_RE = STRING_PATTERNS["concat_chain"]

# Tokeniser used inside _reconstruct_concat to pull each quoted part out of a
# matched concat chain. Compiled once at module load (was recompiled on every
# concat match before).
_CONCAT_TOKEN_RE = re.compile(r'["\']([^"\']*)["\']')


class JSStringsExtractor(JSExtractor):

    def __init__(
        self, filepath, log, exporters=None, index_prefix=None,
        known_benign=False, known_malicious=False, source=None, context=None,
    ):
        super().__init__(
            filepath, log, exporters, index_prefix,
            known_benign, known_malicious, source, context=context,
        )
        self.string_findings = None
        self.log.debug(inspect.currentframe().f_code.co_name)

    def tag(self):
        return Tag.JS_STRINGS.value

    def _decode_hex_string(self, hex_str):
        """Decode \\x41\\x42 style hex strings."""
        try:
            # Remove \\x prefix and decode
            clean = hex_str.replace('\\x', '')
            return bytes.fromhex(clean).decode('utf-8', errors='replace')
        except Exception:
            return None

    def _decode_unicode_string(self, uni_str):
        """Decode \\u0041\\u0042 style unicode strings."""
        try:
            return uni_str.encode('utf-8').decode('unicode_escape')
        except Exception:
            return None

    def _decode_charcode(self, charcode_str):
        """Decode String.fromCharCode(72, 101, 108, ...) sequences."""
        try:
            codes = [int(c.strip()) for c in charcode_str.split(',') if c.strip().isdigit()]
            return ''.join(chr(c) for c in codes if 0 <= c <= 0x10FFFF)
        except Exception:
            return None

    def _decode_base64(self, b64_str):
        """Attempt to decode base64 string."""
        try:
            decoded = base64.b64decode(b64_str)
            # Check if result is printable text
            text = decoded.decode('utf-8', errors='strict')
            # Only return if it looks like text (>80% printable)
            printable = sum(1 for c in text if c.isprintable() or c in '\n\r\t')
            if printable / len(text) > 0.8:
                return text
        except Exception:
            pass
        return None

    def _reconstruct_concat(self, concat_match):
        """Reconstruct concatenated string parts."""
        try:
            parts = _CONCAT_TOKEN_RE.findall(concat_match)
            return ''.join(parts)
        except Exception:
            return None

    def _find_line_number(self, match_start):
        """1-indexed line number for `match_start`, looked up in O(log L) via
        bisect over `self._line_offsets` (built once per extract() call).

        Replaces the historical `self.js_source[:match_start].count('\\n') + 1`
        which was O(N) per call and quadratic across all matches in a sample.
        """
        return bisect.bisect_right(self._line_offsets, match_start)

    def _scan_text(self, text):
        """Run every encoded-string pattern over `text` and return a list of
        finding dicts. Stateless apart from the per-call `_line_offsets` cache,
        which `_find_line_number` reads — callers must reset it before invoking
        this so line numbers reference the text being scanned, not the previous
        one.
        """
        findings = []

        # Hex-encoded strings
        for m in _HEX_STRING_RE.finditer(text):
            raw = m.group()
            decoded = self._decode_hex_string(raw)
            if decoded and len(decoded) >= 4:
                findings.append({
                    'string': decoded[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'hex',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(decoded),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(decoded),
                })

        # Unicode-encoded strings
        for m in _UNICODE_STRING_RE.finditer(text):
            raw = m.group()
            decoded = self._decode_unicode_string(raw)
            if decoded and len(decoded) >= 3:
                findings.append({
                    'string': decoded[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'unicode',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(decoded),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(decoded),
                })

        # String.fromCharCode sequences
        for m in _CHARCODE_RE.finditer(text):
            raw = m.group()
            decoded = self._decode_charcode(m.group(1))
            if decoded and len(decoded) >= 4:
                findings.append({
                    'string': decoded[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'charcode',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(decoded),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(decoded),
                })

        # Base64-encoded strings
        for m in _BASE64_STRING_RE.finditer(text):
            raw = m.group(0)
            b64_val = m.group(1)
            decoded = self._decode_base64(b64_val)
            if decoded and len(decoded) >= 10:
                findings.append({
                    'string': decoded[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'base64',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(decoded),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(decoded),
                })

        # Concatenated strings (reassembled)
        for m in _CONCAT_STRING_RE.finditer(text):
            raw = m.group()
            reconstructed = self._reconstruct_concat(raw)
            if reconstructed and len(reconstructed) >= 20:
                findings.append({
                    'string': reconstructed[:4000],
                    'string_raw': raw[:4000],
                    'string_encoding': 'concat',
                    'string_offset': self._find_line_number(m.start()),
                    'string_length': len(reconstructed),
                    'string_raw_length': len(raw),
                    'string_entropy': self._calculate_text_entropy(reconstructed),
                })

        return findings

    def extract(self):
        src = self.js_source
        if not src:
            return None

        # Pass 1: raw source. _line_offsets is keyed off whichever text is
        # currently being scanned so _find_line_number resolves to that text.
        self._line_offsets = line_offsets(src)
        findings = self._scan_text(src)

        # Pass 2: deobfuscated text, when the deobfuscator produced something
        # meaningfully different. Same patterns, but a different surface — for
        # samples where the encoded payload is hidden behind an outer wrapper
        # (e.g. array.join() + eval in Vjw0rm/WSH-RAT) only this pass yields
        # any rows at all.
        deobf_text, _ = self._context.deobfuscated
        if deobf_text and deobf_text != src:
            self._line_offsets = line_offsets(deobf_text)
            findings.extend(self._scan_text(deobf_text))

        if not findings:
            return None

        # Deduplicate by decoded string value (raw pass wins on collision: it
        # comes first in `findings`). A string that surfaces only in the
        # deobfuscated text still gets persisted, which is the whole point of
        # the second pass.
        seen_values = set()
        deduped = []
        for f in findings:
            val_key = f['string'][:100]
            if val_key not in seen_values:
                seen_values.add(val_key)
                deduped.append(f)

        self.string_findings = deduped[:500]  # Limit per file
        # Publish to the shared context so post-loop consumers (notably the IOC
        # plumbing in workers.py) can scrape the decoded strings without
        # holding a reference to this extractor instance.
        self._context.decoded_strings = self.string_findings
        return self.string_findings

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ClickHouseExporter":
            if not self.string_findings:
                return None

            data = []
            for f in self.string_findings:
                data.append([
                    self.sha256,
                    f['string'],
                    f['string_raw'],
                    f['string_encoding'],
                    f['string_offset'],
                    f['string_length'],
                    f['string_raw_length'],
                    f['string_entropy'],
                ])

            column_names = [
                "sha256",
                "string",
                "string_raw",
                "string_encoding",
                "string_offset",
                "string_length",
                "string_raw_length",
                "string_entropy",
            ]

            column_type_names = [
                "FixedString(64)",
                "String",
                "String",
                "LowCardinality(String)",
                "UInt64",
                "UInt32",
                "UInt32",
                "Float32",
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "code_binja_strings_raw"