Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2232595
paste.php
No One
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Authored By
revi
Jun 19 2024, 14:04
2024-06-19 14:04:04 (UTC+0)
Size
9 KB
Referenced Files
None
Subscribers
None
paste.php
View Options
<?php
final
class
PhabricatorEditorURIEngine
extends
Phobject
{
private
$viewer
;
private
$repository
;
private
$pattern
;
private
$rawTokens
;
private
$repositoryTokens
;
public
static
function
newForViewer
(
PhabricatorUser
$viewer
)
{
if
(
!
$viewer
->
isLoggedIn
(
)
)
{
return
null
;
}
$pattern
=
$viewer
->
getUserSetting
(
PhabricatorEditorSetting
::
SETTINGKEY
)
;
if
(
$pattern
===
null
||
trim
(
$pattern
)
===
''
)
{
return
null
;
}
$engine
=
id
(
new
self
(
)
)
->
setViewer
(
$viewer
)
->
setPattern
(
$pattern
)
;
// If there's a problem with the pattern,
try
{
$engine
->
validatePattern
(
)
;
}
catch
(
PhabricatorEditorURIParserException
$ex
)
{
return
null
;
}
return
$engine
;
}
public
function
setViewer
(
PhabricatorUser
$viewer
)
{
$this
->
viewer
=
$viewer
;
return
$this
;
}
public
function
getViewer
(
)
{
return
$this
->
viewer
;
}
public
function
setRepository
(
PhabricatorRepository
$repository
)
{
$this
->
repository
=
$repository
;
return
$this
;
}
public
function
getRepository
(
)
{
return
$this
->
repository
;
}
public
function
setPattern
(
$pattern
)
{
$this
->
pattern
=
$pattern
;
return
$this
;
}
public
function
getPattern
(
)
{
return
$this
->
pattern
;
}
public
function
validatePattern
(
)
{
$this
->
getRawURITokens
(
)
;
return
true
;
}
public
function
getURIForPath
(
$path
,
$line
)
{
$tokens
=
$this
->
getURITokensForRepository
(
$path
)
;
$variables
=
array
(
'f'
=>
$this
->
escapeToken
(
$path
)
,
'l'
=>
$this
->
escapeToken
(
$line
)
,
)
;
$tokens
=
$this
->
newTokensWithVariables
(
$tokens
,
$variables
)
;
return
$this
->
newStringFromTokens
(
$tokens
)
;
}
public
function
getURITokensForPath
(
$path
)
{
$tokens
=
$this
->
getURITokensForRepository
(
$path
)
;
$variables
=
array
(
'f'
=>
$this
->
escapeToken
(
$path
)
,
)
;
return
$this
->
newTokensWithVariables
(
$tokens
,
$variables
)
;
}
public
static
function
getVariableDefinitions
(
)
{
return
array
(
'f'
=>
array
(
'name'
=>
pht
(
'File Name'
)
,
'example'
=>
pht
(
'path/to/source.c'
)
,
)
,
'l'
=>
array
(
'name'
=>
pht
(
'Line Number'
)
,
'example'
=>
'777'
,
)
,
'n'
=>
array
(
'name'
=>
pht
(
'Repository Short Name'
)
,
'example'
=>
'arcanist'
,
)
,
'd'
=>
array
(
'name'
=>
pht
(
'Repository ID'
)
,
'example'
=>
'42'
,
)
,
'p'
=>
array
(
'name'
=>
pht
(
'Repository PHID'
)
,
'example'
=>
'PHID-REPO-abcdefghijklmnopqrst'
,
)
,
'r'
=>
array
(
'name'
=>
pht
(
'Repository Callsign'
)
,
'example'
=>
'XYZ'
,
)
,
'%'
=>
array
(
'name'
=>
pht
(
'Literal Percent Symbol'
)
,
'example'
=>
'%'
,
)
,
)
;
}
private
function
getURITokensForRepository
(
)
{
if
(
!
$this
->
repositoryTokens
)
{
$this
->
repositoryTokens
=
$this
->
newURITokensForRepository
(
)
;
}
return
$this
->
repositoryTokens
;
}
private
function
newURITokensForRepository
(
)
{
$tokens
=
$this
->
getRawURITokens
(
)
;
$repository
=
$this
->
getRepository
(
)
;
if
(
!
$repository
)
{
throw
new
PhutilInvalidStateException
(
'setRepository'
)
;
}
$variables
=
array
(
'r'
=>
$this
->
escapeToken
(
$repository
->
getCallsign
(
)
)
,
'n'
=>
$this
->
escapeToken
(
$repository
->
getRepositorySlug
(
)
)
,
'd'
=>
$this
->
escapeToken
(
$repository
->
getID
(
)
)
,
'p'
=>
$this
->
escapeToken
(
$repository
->
getPHID
(
)
)
,
)
;
return
$this
->
newTokensWithVariables
(
$tokens
,
$variables
)
;
}
private
function
getRawURITokens
(
)
{
if
(
!
$this
->
rawTokens
)
{
$this
->
rawTokens
=
$this
->
newRawURITokens
(
)
;
}
return
$this
->
rawTokens
;
}
private
function
newRawURITokens
(
)
{
$raw_pattern
=
$this
->
getPattern
(
)
;
$raw_tokens
=
self
::
newPatternTokens
(
$raw_pattern
)
;
$variable_definitions
=
self
::
getVariableDefinitions
(
)
;
foreach
(
$raw_tokens
as
$token
)
{
if
(
$token
[
'type'
]
!==
'variable'
)
{
continue
;
}
$value
=
$token
[
'value'
]
;
if
(
isset
(
$variable_definitions
[
$value
]
)
)
{
continue
;
}
throw
new
PhabricatorEditorURIParserException
(
pht
(
'Editor pattern "%s" is invalid: the pattern contains an '
.
'unrecognized variable ("%s"). Use "%%%%" to encode a literal '
.
'percent symbol.'
,
$raw_pattern
,
'%'
.
$value
)
)
;
}
$variables
=
array
(
'%'
=>
'%'
,
)
;
$tokens
=
$this
->
newTokensWithVariables
(
$raw_tokens
,
$variables
)
;
$first_literal
=
null
;
if
(
$tokens
)
{
foreach
(
$tokens
as
$token
)
{
if
(
$token
[
'type'
]
===
'literal'
)
{
$first_literal
=
$token
[
'value'
]
;
}
break
;
}
if
(
$first_literal
===
null
)
{
throw
new
PhabricatorEditorURIParserException
(
pht
(
'Editor pattern "%s" is invalid: the pattern must begin with '
.
'a valid editor protocol, but begins with a variable. This is '
.
'very sneaky and also very forbidden.'
,
$raw_pattern
)
)
;
}
}
$uri
=
new
PhutilURI
(
$first_literal
)
;
$editor_protocol
=
$uri
->
getProtocol
(
)
;
if
(
!
$editor_protocol
)
{
throw
new
PhabricatorEditorURIParserException
(
pht
(
'Editor pattern "%s" is invalid: the pattern must begin with '
.
'a valid editor protocol, but does not begin with a recognized '
.
'protocol string.'
,
$raw_pattern
)
)
;
}
$allowed_key
=
'uri.allowed-editor-protocols'
;
$allowed_protocols
=
PhabricatorEnv
::
getEnvConfig
(
$allowed_key
)
;
if
(
empty
(
$allowed_protocols
[
$editor_protocol
]
)
)
{
throw
new
PhabricatorEditorURIParserException
(
pht
(
'Editor pattern "%s" is invalid: the pattern must begin with '
.
'a valid editor protocol, but the protocol "%s://" is not allowed.'
,
$raw_pattern
,
$editor_protocol
)
)
;
}
return
$tokens
;
}
private
function
newTokensWithVariables
(
array
$tokens
,
array
$variables
)
{
// Replace all "variable" tokens that we have replacements for with
// the literal value.
foreach
(
$tokens
as
$key
=>
$token
)
{
$type
=
$token
[
'type'
]
;
if
(
$type
==
'variable'
)
{
$variable
=
$token
[
'value'
]
;
if
(
isset
(
$variables
[
$variable
]
)
)
{
$tokens
[
$key
]
=
array
(
'type'
=>
'literal'
,
'value'
=>
$variables
[
$variable
]
,
)
;
}
}
}
// Now, merge sequences of adjacent "literal" tokens into a single token.
$last_literal
=
null
;
foreach
(
$tokens
as
$key
=>
$token
)
{
$is_literal
=
(
$token
[
'type'
]
===
'literal'
)
;
if
(
!
$is_literal
)
{
$last_literal
=
null
;
continue
;
}
if
(
$last_literal
!==
null
)
{
$tokens
[
$key
]
[
'value'
]
=
$tokens
[
$last_literal
]
[
'value'
]
.
$token
[
'value'
]
;
unset
(
$tokens
[
$last_literal
]
)
;
}
$last_literal
=
$key
;
}
$tokens
=
array_values
(
$tokens
)
;
return
$tokens
;
}
private
function
escapeToken
(
$token
)
{
// Paths are user controlled, so a clever user could potentially make
// editor links do surprising things with paths containing "/../".
// Find anything that looks like "/../" and mangle it.
$token
=
preg_replace
(
'((^|/)\.\.(/|\z))'
,
'\1dot-dot\2'
,
$token
)
;
return
phutil_escape_uri
(
$token
)
;
}
private
function
newStringFromTokens
(
array
$tokens
)
{
$result
=
array
(
)
;
foreach
(
$tokens
as
$token
)
{
$token_type
=
$token
[
'type'
]
;
$token_value
=
$token
[
'value'
]
;
$is_literal
=
(
$token_type
===
'literal'
)
;
if
(
!
$is_literal
)
{
throw
new
Exception
(
pht
(
'Editor pattern token list can not be converted into a string: '
.
'it still contains a non-literal token ("%s", of type "%s").'
,
$token_value
,
$token_type
)
)
;
}
$result
[
]
=
$token_value
;
}
$result
=
implode
(
''
,
$result
)
;
return
$result
;
}
public
static
function
newPatternTokens
(
$raw_pattern
)
{
$token_positions
=
array
(
)
;
$len
=
strlen
(
$raw_pattern
)
;
for
(
$ii
=
0
;
$ii
<
$len
;
$ii
++
)
{
$c
=
$raw_pattern
[
$ii
]
;
if
(
$c
===
'%'
)
{
if
(
!
isset
(
$raw_pattern
[
$ii
+
1
]
)
)
{
throw
new
PhabricatorEditorURIParserException
(
pht
(
'Editor pattern "%s" is invalid: the final character in a '
.
'pattern may not be an unencoded percent symbol ("%%"). '
.
'Use "%%%%" to encode a literal percent symbol.'
,
$raw_pattern
)
)
;
}
$token_positions
[
]
=
$ii
;
$ii
++
;
}
}
// Add a final marker past the end of the string, so we'll collect any
// trailing literal bytes.
$token_positions
[
]
=
$len
;
$tokens
=
array
(
)
;
$cursor
=
0
;
foreach
(
$token_positions
as
$pos
)
{
$token_len
=
(
$pos
-
$cursor
)
;
if
(
$token_len
>
0
)
{
$tokens
[
]
=
array
(
'type'
=>
'literal'
,
'value'
=>
substr
(
$raw_pattern
,
$cursor
,
$token_len
)
,
)
;
}
$cursor
=
$pos
;
if
(
$cursor
<
$len
)
{
$tokens
[
]
=
array
(
'type'
=>
'variable'
,
'value'
=>
substr
(
$raw_pattern
,
$cursor
+
1
,
1
)
,
)
;
}
$cursor
=
$pos
+
2
;
}
return
$tokens
;
}
}
File Metadata
Details
Attached
Mime Type
text/plain; charset=utf-8
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
731676
Default Alt Text
paste.php (9 KB)
Attached To
Mode
P43 paste.php
Attached
Detach File
Event Timeline
Log In to Comment