History log of /dokuwiki/ (Results 76 – 100 of 10912)
Revision Date Author Comments
(<<< Hide modified files)
(Show modified files >>>)
879510b407-Jun-2026 splitbrain <86426+splitbrain@users.noreply.github.com>

�� Update deleted files

b12755b007-Jun-2026 Andreas Gohr <andi@splitbrain.org>

Make common_pageinfo tests independent of execution order

The pageinfo() tests relied on running in a fixed order: test_editor_and_externaledits
mutated wiki:syntax (changelog entry + file mtime), a

Make common_pageinfo tests independent of execution order

The pageinfo() tests relied on running in a fixed order: test_editor_and_externaledits
mutated wiki:syntax (changelog entry + file mtime), and the other tests relied on
that page being pristine. Move the mutating test to its own page (wiki:dokuwiki) so
the shared per-class data dir stays clean, prime the last_change metadata within each
test instead of across tests, and fix the affected expectations. The suite now passes
in isolation and in random/reverse order.

While here, modernize the file:
- capture the pageinfo() result once instead of calling it twice
- add public/protected visibility markers to all methods
- convert array() to the short [] syntax
- replace the deprecated addLogEntry() with the PageFile API it wraps

show more ...

2cc228b606-Jun-2026 Andreas Gohr <andi@splitbrain.org>

Read REMOTE_USER through $INPUT in the RPC servers

Route the logged-in check that selects between a 401 and 403 response
through the $INPUT abstraction instead of reading the $_SERVER
superglobal di

Read REMOTE_USER through $INPUT in the RPC servers

Route the logged-in check that selects between a 401 and 403 response
through the $INPUT abstraction instead of reading the $_SERVER
superglobal directly. This matches how the rest of both servers already
read request data and lets tests exercise both branches by setting the
server value via $INPUT.

show more ...

17acbd0f06-Jun-2026 Andreas Gohr <andi@splitbrain.org>

Cast the ACL permission to an integer when saving the rule table

The bulk update path pulled the permission map straight from input and
wrote each value verbatim into a tab-separated ACL line, while

Cast the ACL permission to an integer when saving the rule table

The bulk update path pulled the permission map straight from input and
wrote each value verbatim into a tab-separated ACL line, while the
single-rule path already read it through an integer filter. A non-integer
value could carry a newline or tab and inject extra rules into the file.
Cast to int so the value can only ever be a single permission number.

This was not exploitable: the rule table is reachable only through the
ACL admin plugin, which is superuser-only and CSRF-protected, and a
superuser can already edit the ACL file directly. The cast is hardening
for consistency with the single-rule path.

show more ...

92a018d906-Jun-2026 Andreas Gohr <andi@splitbrain.org>

Remove unused legacy image resize and crop functions

media_resize_imageIM(), media_crop_imageIM() and media_resize_imageGD()
were superseded by the Slika library years ago (two were already marked
d

Remove unused legacy image resize and crop functions

media_resize_imageIM(), media_crop_imageIM() and media_resize_imageGD()
were superseded by the Slika library years ago (two were already marked
deprecated in 2020). They had no callers left in core, and a search of
the published plugin and template ecosystem found no external callers
either.

show more ...

795d841906-Jun-2026 Andreas Gohr <andi@splitbrain.org>

Read the code block download offset as an integer

The named code/file block download link reads the codeblockOffset
request parameter and adds it to the current block index to build the
export link.

Read the code block download offset as an integer

The named code/file block download link reads the codeblockOffset
request parameter and adds it to the current block index to build the
export link. The value was read as a string and then used in arithmetic.
On PHP 8 a non-numeric value turns that addition into a string + int
operation, which throws a TypeError and produces a fatal error when
rendering any page that contains a named code or file block.

The offset is now read with $INPUT->int(), which yields 0 for absent,
empty or non-numeric input and the integer value otherwise, so the
arithmetic is always int + int. The has() guard and zero initialiser
are no longer needed.

show more ...

fa03edf306-Jun-2026 Andreas Gohr <andi@splitbrain.org>

(security) Enforce per-page edit permission in the revert plugin

The revert manager is accessible to managers, not just admins. Its
reversion loop called saveWikiText() for every submitted page id w

(security) Enforce per-page edit permission in the revert plugin

The revert manager is accessible to managers, not just admins. Its
reversion loop called saveWikiText() for every submitted page id without
checking the per-page ACL, relying only on the manager role. A manager
denied edit on a namespace could therefore revert those pages to an
older revision or blank them entirely (low severity).

The page listing already hid unreadable pages, but offered every
readable page for reversion, including ones the manager could not edit.
A hand-crafted POST could also target arbitrary ids regardless of what
the listing showed.

Each id is now cleaned and checked for edit permission before it is
reverted; ids that fail the check are silently skipped. The listing
additionally only offers pages the manager actually has edit permission
on, so the form and the action agree.

show more ...

37bd308a06-Jun-2026 Andreas Gohr <andi@splitbrain.org>

Add unit tests for the Draft class

The Draft class had no dedicated tests. Cover the save/retrieve round
trip for whole-page and section edits, the cases where no draft is
written (drafts disabled,

Add unit tests for the Draft class

The Draft class had no dedicated tests. Cover the save/retrieve round
trip for whole-page and section edits, the cases where no draft is
written (drafts disabled, nothing edited), draft deletion, reading a
missing draft, and the constructor's purging of drafts that predate the
current page revision.

show more ...

5d8c9d4206-Jun-2026 Andreas Gohr <andi@splitbrain.org>

(security) Require a security token for the lock AJAX call

The lock AJAX call refreshes the edit lock and saves a draft, both of
which change server state. It was gated only by the write ACL and,
un

(security) Require a security token for the lock AJAX call

The lock AJAX call refreshes the edit lock and saves a draft, both of
which change server state. It was gated only by the write ACL and,
unlike the sibling draft-delete call, did not verify a security token
(low severity).

A cross-site forged POST against a logged-in user could, within that
user's own write permissions, take or hold an edit lock and store
attacker-controlled draft content under their name.

The call now verifies the security token before taking the lock or
saving the draft. Logged out users are unaffected, as no token is
issued or checked for them. The edit lock timer now always sends the
token with its refresh request, including when draft saving is
disabled.

show more ...

aabc478206-Jun-2026 Andreas Gohr <andi@splitbrain.org>

(security) Add CSRF protection and use Form class in popularity plugin

The plugin is accessible to managers, not just admins, and had two
separate issues.

1. Missing CSRF token (low severity)
Th

(security) Add CSRF protection and use Form class in popularity plugin

The plugin is accessible to managers, not just admins, and had two
separate issues.

1. Missing CSRF token (low severity)
The handler accepted the posted data and toggled autosubmit without
checking a security token. A cross-site forged POST against a logged-in
manager could enable autosubmit and trigger a submission of the wiki's
data to the popularity server.
2. Reflected XSS (low severity)
When a submission failed, the posted data was reflected back into a
readonly textarea without escaping. A value closing the textarea early
(eg. </textarea><script>...) could inject script into the manager's
browser.
To exploit this, not only a CSRF attack against an authenticated
manager was needed, also the connection to the DokuWiki popularity
server needed to fail.

The popularity plugin now verifies the security token before it sends
data or toggles the autosubmit option.

The form is now built via the the Form API so the textarea value is
escaped automatically. The security token is emitted automatically.
The fallback browser-submission form posts to an external server and is
built without the security token.

show more ...

e8c9256a06-Jun-2026 Andreas Gohr <andi@splitbrain.org>

(security) Clean the media upload namespace in AJAX upload

The namespace passed to the AJAX backend was not cleaned correctly,
resulting in two separate issues.

1. Theoretical Reflected XSS
The

(security) Clean the media upload namespace in AJAX upload

The namespace passed to the AJAX backend was not cleaned correctly,
resulting in two separate issues.

1. Theoretical Reflected XSS
The raw namespace was reflected into the JSON response and injected
into the mediamanager DOM. However since the media manager only
passes cleaned namespaces to AJAX and the ajax backen only returns
JSON, this issue was not exploitable.
2. Cross-namespace ACL bypass (medium severity)
The uncleaned namespace was directly used to check ACLs. In a wiki
where a user has upload permission in a namespace above a namespace
where they don't have permissions (eg. upload allowed in :user:*, but
upload denied in :user:secret:*) they could pass an upper case
namespace (eg :user:SECRET) - no ACL does exist for this upper case
namespace and the acl of the namespace above applies (:user).
When the file is written a cleanID is applied to the full filename,
turning the uppercase namespace into lowercase.
This can allow users to write into a namespace they normally should
not be allowed to write to, but it does require upload permissions in
a higher namespace.

show more ...

3990423504-Jun-2026 Andreas Gohr <gohr@cosmocode.de>

Emit a guard newline in TextareaElement to preserve leading newlines

A browser's HTML parser ignores a single newline immediately after a
<textarea> start tag, so a value whose first character is a

Emit a guard newline in TextareaElement to preserve leading newlines

A browser's HTML parser ignores a single newline immediately after a
<textarea> start tag, so a value whose first character is a newline lost
it on round-trip (e.g. saving a page or section whose source starts with
a blank line silently dropped that line).

Emit a guard newline right after the start tag so the one the browser
drops is absorbed and the value stays intact.

show more ...

4b31eadf04-Jun-2026 Andreas Gohr <gohr@cosmocode.de>

fix (parsing): avoid newline loss on GFM section editing

The GFM header parsing returned a byte position pointing at the newline
before the actual header resulting in the observed newline eatings as

fix (parsing): avoid newline loss on GFM section editing

The GFM header parsing returned a byte position pointing at the newline
before the actual header resulting in the observed newline eatings as
reported in https://github.com/dokuwiki/dokuwiki/pull/4636#issuecomment-4491970909

Additionally this fixes an oddity of DW header parsing which
accidentally allowed text on the line before the opening = chars.
Whitespace is still allowed.

show more ...

2e43b79904-Jun-2026 Andreas Gohr <gohr@cosmocode.de>

Render locale and plugin-bundled text as DokuWiki syntax

Static "intro" text shipped with DokuWiki, templates and plugins —
inc/lang/*/*.txt, template locale files, each plugin's lang/<lc>/*.txt —
i

Render locale and plugin-bundled text as DokuWiki syntax

Static "intro" text shipped with DokuWiki, templates and plugins —
inc/lang/*/*.txt, template locale files, each plugin's lang/<lc>/*.txt —
is authored in DokuWiki syntax. It is a core/plugin asset, not user
content. When an admin configures the wiki for Markdown the DW link and
monospace modes are not loaded, so these files render as literal text:
[[wiki:syntax]] and ''Save'' pairs survive into the HTML.

Pin those entry points to the 'dw' flavour via the override added in the
previous commit:

- p_locale_xhtml() and tpl_locale_xhtml() pass 'dw'.
- PluginTrait::locale_xhtml() passes 'dw'.
- PluginTrait::render_text() / PluginInterface::render_text() gain a
$syntax parameter defaulting to 'dw'. The default is 'dw', not null,
because the method predates GFM and its callers pass DW-syntax strings;
plugins rendering user content opt back into the configured syntax with
render_text($text, 'xhtml', null).

Locale output is now deterministic across a syntax switch, so its caches
get over-invalidated but never under-invalidated — acceptable, as the
locale render path is rare and cheap.

show more ...

16999ed104-Jun-2026 Andreas Gohr <gohr@cosmocode.de>

parserutils: allow callers to override the parse syntax, key cache on it

With the registry now carrying the flavour as a parameter, expose that
to callers: p_get_instructions(), p_cached_instruction

parserutils: allow callers to override the parse syntax, key cache on it

With the registry now carrying the flavour as a parameter, expose that
to callers: p_get_instructions(), p_cached_instructions() and
p_cached_output() gain an optional $syntax argument. null (the default)
means "use the configured $conf['syntax']", preserving behaviour for
every existing call site; an explicit flavour parses under it regardless
of the wiki's configured preference.

This is what lets bundled assets render deterministically — e.g. a
plugin forcing 'dw' on a document whose configured syntax is 'md'.

Because that case renders the same file under two flavours within one
request, key both the in-request memo (the $run map) and the on-disk
cache on $syntax so the two do not collide. The syntax enters the cache
key only when passed explicitly (non-null); when null the key is
unchanged, so existing caches are untouched. Plumbed through new
optional $syntax args on CacheParser / CacheInstructions, appended to
the key string.

show more ...

47a02a1004-Jun-2026 Andreas Gohr <gohr@cosmocode.de>

Parsing: make parse syntax a per-parse value, drop ModeInterface

The active parse's syntax flavour is a per-parse question, not process-
global state: within a single request a plugin can render bun

Parsing: make parse syntax a per-parse value, drop ModeInterface

The active parse's syntax flavour is a per-parse question, not process-
global state: within a single request a plugin can render bundled
DokuWiki-syntax text inside an otherwise-Markdown page. Yet ModeRegistry
was a singleton that read $conf['syntax'] and the $PARSER_MODES global,
and every mode reached it through ModeRegistry::getInstance() — so the
flavour lived in shared mutable state that two parses in one request
would fight over.

Make the registry a short-lived value instead:

- ModeRegistry is constructed once per parse with an explicit $syntax
and injected into Parser, Handler and every mode. getSyntax() /
isDwPreferred() / isMdPreferred() consult $this->syntax; the
DOKU_UNITTEST-gated mode-list cache hack is gone (each registry is
fresh, nothing to invalidate).
- p_get_instructions() is now the single place in the pipeline where
$conf['syntax'] is read; from there the flavour travels as a
parameter. No code under inc/Parsing/ reads $conf['syntax'] directly
anymore — the five syntax-reading modes (Preformatted, GfmHr,
GfmEscape, Externallink, GfmQuote) route through $this->registry.

Keep the two concepts apart, as documented in the ModeRegistry and
AbstractMode docblocks: the user's configured *preference* stays in
$conf['syntax'] for UI code (toolbar, settings), while the active
parse's syntax is a parameter carried by the registry.

$PARSER_MODES is demoted to a deprecated, read-only mirror, published
during loadPluginModes() — third-party syntax plugins (columnlist,
alphalist2, phpwikify, skipentity) and the bundled info plugin read the
global directly, often from their constructors, so the taxonomy must
stay visible there. No core code reads the mirror.

Fold ModeInterface into AbstractMode while here: getSort()/handle() are
abstract, the connect callbacks carry defaults, and the public $Lexer
"FIXME should be done by setter" becomes setLexer()/getLexer() injected
by Parser::addMode() alongside the registry. Nested-content resolution
moves to the allowedCategories()/filterAllowedModes() hooks, resolved
once when the registry is attached.

Tests build their own parser/registry through ParserTestBase::setSyntax()
instead of mutating $conf and calling the removed ModeRegistry::reset().

show more ...


_test/bootstrap.php
_test/tests/Parsing/HandlerTest.php
_test/tests/Parsing/Lexer/RecordingHandler.php
_test/tests/Parsing/Markdown/GfmSpecTest.php
_test/tests/Parsing/ModeRegistryTest.php
_test/tests/Parsing/ParserMode/ExternallinkTest.php
_test/tests/Parsing/ParserMode/GfmBacktickDoubleTest.php
_test/tests/Parsing/ParserMode/GfmBacktickSingleTest.php
_test/tests/Parsing/ParserMode/GfmCodeTest.php
_test/tests/Parsing/ParserMode/GfmDeletedTest.php
_test/tests/Parsing/ParserMode/GfmEmphasisStrongTest.php
_test/tests/Parsing/ParserMode/GfmEmphasisStrongUnderscoreTest.php
_test/tests/Parsing/ParserMode/GfmEmphasisTest.php
_test/tests/Parsing/ParserMode/GfmEmphasisUnderscoreTest.php
_test/tests/Parsing/ParserMode/GfmEscapeTest.php
_test/tests/Parsing/ParserMode/GfmFileTest.php
_test/tests/Parsing/ParserMode/GfmHeaderTest.php
_test/tests/Parsing/ParserMode/GfmHrTest.php
_test/tests/Parsing/ParserMode/GfmLinebreakTest.php
_test/tests/Parsing/ParserMode/GfmLinkTest.php
_test/tests/Parsing/ParserMode/GfmListblockTest.php
_test/tests/Parsing/ParserMode/GfmMediaTest.php
_test/tests/Parsing/ParserMode/GfmQuoteTest.php
_test/tests/Parsing/ParserMode/GfmStrongUnderscoreTest.php
_test/tests/Parsing/ParserMode/ParserTestBase.php
_test/tests/Parsing/ParserMode/PreformattedTest.php
inc/Extension/SyntaxPlugin.php
inc/Parsing/Handler.php
inc/Parsing/ModeRegistry.php
inc/Parsing/Parser.php
inc/Parsing/ParserMode/AbstractFormatting.php
inc/Parsing/ParserMode/AbstractMode.php
inc/Parsing/ParserMode/Base.php
inc/Parsing/ParserMode/Eol.php
inc/Parsing/ParserMode/Externallink.php
inc/Parsing/ParserMode/Footnote.php
inc/Parsing/ParserMode/GfmBacktickSingle.php
inc/Parsing/ParserMode/GfmCode.php
inc/Parsing/ParserMode/GfmEscape.php
inc/Parsing/ParserMode/GfmHr.php
inc/Parsing/ParserMode/GfmHtmlEntity.php
inc/Parsing/ParserMode/GfmListblock.php
inc/Parsing/ParserMode/GfmQuote.php
inc/Parsing/ParserMode/GfmTable.php
inc/Parsing/ParserMode/Listblock.php
inc/Parsing/ParserMode/Preformatted.php
inc/Parsing/ParserMode/Table.php
inc/deprecated.php
inc/parserutils.php
3e42782802-Jun-2026 Wizzard <wizzardsk@gmail.com>

Translation update (sk)

b8c2692f29-May-2026 Andreas Gohr <andi@splitbrain.org>

fix(httputils): build a proper internal URL for nginx X-Accel-Redirect

Unlike Apache's mod_xsendfile and lighttpd's X-LIGHTTPD-send-file,
which both accept an absolute file system path and stream th

fix(httputils): build a proper internal URL for nginx X-Accel-Redirect

Unlike Apache's mod_xsendfile and lighttpd's X-LIGHTTPD-send-file,
which both accept an absolute file system path and stream the file
directly, nginx treats X-Accel-Redirect as a URL: it performs an
internal subrequest against the value and resolves it through
`internal` location blocks in its own configuration. The redirect
target therefore must be a request path nginx can map back to a file,
not the file system path itself.

The previous implementation blindly stripped DOKU_INC's length from
the file path, which produced a broken URL whenever a data directory
had been relocated outside the DokuWiki tree.

Route the file through three cases instead: files inside DOKU_INC keep
their path relative to the wiki root; files in a relocated mediadir,
mediaolddir, cachedir or savedir are mapped back to their default URL
below data/; everything else falls through an opt-in /_x_accel_redirect/
prefix.

Path segments are URL-encoded so filenames with spaces or other
special characters resolve (fixes another potential bug in the previous
implementation).

Nginx configuration:

For the default layout no extra configuration is needed - files keep
their path relative to the wiki root and the regular wiki location
already serves them. For relocated data directories admins must add an
`internal` location below the wiki's URL space pointing at the actual
file system path, e.g.:

location /data/media/ { internal; alias /srv/dokuwiki-media/; }

For the /_x_accel_redirect/ fallback (used when a plugin serves files
from outside the wiki and its data directories), admins opt in by
adding:

location /_x_accel_redirect/ { internal; alias /; }

When the wiki is installed under a sub path, prefix both locations
accordingly (e.g. /wiki/data/media/ and /wiki/_x_accel_redirect/).

fixes: #2895

show more ...

54e7626029-May-2026 Andreas Gohr <andi@splitbrain.org>

chore: adjust overlong line

7e687fd829-May-2026 Andreas Gohr <andi@splitbrain.org>

fix(auth): scope media ACL checks to the namespace

Media files have no per-file ACLs; permissions must be evaluated against
the namespace they live in. Several call sites passed the raw media ID
to

fix(auth): scope media ACL checks to the namespace

Media files have no per-file ACLs; permissions must be evaluated against
the namespace they live in. Several call sites passed the raw media ID
to auth_quickaclcheck(), so a page-intended exact-ID rule (e.g. on
wiki:secret.png) could silently apply to a media file sharing that ID.

Introduce mediaAclPath() that builds the correct namespace wildcard
path (handling root-namespace media) and route all media-related ACL
checks through it. Also normalize the lone `:X` sentinel variant in
fetch.functions.php to the standard `:*` form.

fixes: #4647

show more ...

6e39b4e328-May-2026 Andreas Gohr <andi@splitbrain.org>

refactor(search): extract LegacyIndexer wrapper for BC contract

Move the deprecated helpers (lookupKey, addMetaKeys, renameMetaValue,
getPID, lookup) off Indexer and into a new LegacyIndexer wrapper

refactor(search): extract LegacyIndexer wrapper for BC contract

Move the deprecated helpers (lookupKey, addMetaKeys, renameMetaValue,
getPID, lookup) off Indexer and into a new LegacyIndexer wrapper. The
wrapper also restores the Doku_Indexer return contract (true|string)
around addPage/deletePage/renamePage/clear so plugins using the legacy
API keep working without try/catch.

idx_get_indexer() now returns the LegacyIndexer; getPages stays on
Indexer because plugins call it directly on Indexer instances.

fixes #4645

show more ...

1dbc46ac27-May-2026 Tzipirigu <tzipirigu.radu25683@gmail.com>

Translation update (ro)

4f32c45b26-May-2026 Andreas Gohr <gohr@cosmocode.de>

GfmLink: allow soft line break inside link text

The label character class explicitly forbade `\n`, so a CommonMark
soft line break inside link text (e.g. `[link with<EOL>more](url)`)
fell through to

GfmLink: allow soft line break inside link text

The label character class explicitly forbade `\n`, so a CommonMark
soft line break inside link text (e.g. `[link with<EOL>more](url)`)
fell through to literal text instead of producing a link. Loosen the
class to accept a bare `\n` as long as it is not followed by a blank
line — soft breaks are spec-allowed inside link text, blank lines are
not, and refusing them also keeps `\n#`-anchored block modes (header,
hr, ...) from being swallowed by a runaway link match.

The `\n` survives into the label string and renders as a literal line
ending in HTML, which browsers display as a single space. This soft
break behavior has been checked against
https://spec.commonmark.org/dingus/

Note that this behavior differs from github where the line break is
rendered as a hard break <br>.

show more ...

65dd204226-May-2026 Andreas Gohr <gohr@cosmocode.de>

GfmEscape: defer \\<EOL> to DW Linebreak in mixed-syntax modes

Both GfmEscape (sort 5) and DW Linebreak (sort 140) can claim the
two backslashes of `\\` followed by space/tab/newline. The lexer's
ti

GfmEscape: defer \\<EOL> to DW Linebreak in mixed-syntax modes

Both GfmEscape (sort 5) and DW Linebreak (sort 140) can claim the
two backslashes of `\\` followed by space/tab/newline. The lexer's
tie-breaker picked GfmEscape, so DW's forced linebreak silently lost
its delimiter under dw+md and md+dw. Add a negative lookahead that
declines `\\[ \t\n]` whenever DW syntax is loaded — pure md keeps
GFM-spec behavior. Mid-line `\\` (UNC paths etc.) still escapes.

show more ...

1536bca224-May-2026 Kishore D Rajegowda <kishore328@gmail.com>

fix(locktimer): reset lock timer on paste and other input events

The lock-timer handler was bound only to `keypress`, which fires for
character key presses but not for paste via right-click menu,
dr

fix(locktimer): reset lock timer on paste and other input events

The lock-timer handler was bound only to `keypress`, which fires for
character key presses but not for paste via right-click menu,
drag-and-drop, or other non-keyboard input methods. Users editing a
page solely by pasting could therefore lose their page lock after the
configured timeout despite active editing.

Switch the binding to the `input` event, which fires on every value
change of the textarea regardless of source (typing, paste via any
method, cut, drag-drop, undo/redo). This is a superset of the previous
behaviour, so no editing action regresses.

Fixes #3714

show more ...

12345678910>>...437