mirror of
https://github.com/github/codeql.git
synced 2026-05-01 11:45:14 +02:00
Convert Apache misc text models to CSV taint-flow specifications
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSteps
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
/**
|
||||
* The class `org.apache.commons.lang.RandomStringUtils` or `org.apache.commons.lang3.RandomStringUtils`.
|
||||
@@ -212,137 +213,166 @@ private class ApacheStrBuilderTaintWriter extends ApacheStrBuilderCallable, Tain
|
||||
}
|
||||
}
|
||||
|
||||
private class ApacheWordUtilsTaintPreservingMethod extends TaintPreservingCallable {
|
||||
ApacheWordUtilsTaintPreservingMethod() {
|
||||
this.getDeclaringType()
|
||||
.hasQualifiedName(["org.apache.commons.lang3.text", "org.apache.commons.text"], "WordUtils") and
|
||||
this.getReturnType() instanceof TypeString
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) {
|
||||
this.getParameterType(arg) instanceof TypeString and
|
||||
arg != 4 // Exclude the wrapOn parameter from `wrap(String, int, String, boolean, String)`
|
||||
}
|
||||
}
|
||||
|
||||
private class ApacheStrTokenizer extends RefType {
|
||||
ApacheStrTokenizer() {
|
||||
this.hasQualifiedName(["org.apache.commons.lang3.text", "org.apache.commons.text"],
|
||||
"StrTokenizer") or
|
||||
this.hasQualifiedName("org.apache.commons.text", "StringTokenizer")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable that sets the string to be tokenized by an Apache Commons `Str[ing]Tokenizer`.
|
||||
*
|
||||
* Note `reset` is an instance method that taints an existing instance; all others return a fresh instance.
|
||||
* Taint-propagating models for `WordUtils`.
|
||||
*/
|
||||
private class ApacheStrTokenizerTaintingMethod extends TaintPreservingCallable {
|
||||
ApacheStrTokenizerTaintingMethod() {
|
||||
this.getDeclaringType() instanceof ApacheStrTokenizer and
|
||||
(
|
||||
this instanceof Constructor or
|
||||
this.getName() in ["getCSVInstance", "getTSVInstance", "reset"]
|
||||
)
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { arg = 0 }
|
||||
|
||||
override predicate transfersTaint(int fromArg, int toArg) {
|
||||
this.getName() = "reset" and
|
||||
returnsTaintFrom(fromArg) and
|
||||
toArg = -1
|
||||
}
|
||||
}
|
||||
|
||||
private class ApacheStrTokenizerTaintGetter extends TaintPreservingCallable {
|
||||
ApacheStrTokenizerTaintGetter() {
|
||||
this.getDeclaringType() instanceof ApacheStrTokenizer and
|
||||
this.getName() in [
|
||||
"getContent", "getTokenArray", "getTokenList", "nextToken", "previousToken", "toString"
|
||||
private class ApacheWordUtilsModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3.text;WordUtils;false;wrap;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean,java.lang.String);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;uncapitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;swapCase;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalize;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;initials;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;initials;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalizeFully;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;wrap;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean,java.lang.String);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;uncapitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;swapCase;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalize;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;abbreviate;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;abbreviate;;;Argument[3];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;initials;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;initials;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalizeFully;(java.lang.String,char[]);;Argument[0];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { arg = -1 }
|
||||
}
|
||||
|
||||
private class ApacheStrLookup extends RefType {
|
||||
ApacheStrLookup() {
|
||||
this.hasQualifiedName("org.apache.commons.lang3.text", "StrLookup") or
|
||||
this.hasQualifiedName("org.apache.commons.text.lookup", "StringLookup")
|
||||
}
|
||||
}
|
||||
|
||||
private class ApacheStringLookupFactory extends RefType {
|
||||
ApacheStringLookupFactory() {
|
||||
this.hasQualifiedName("org.apache.commons.text.lookup", "StringLookupFactory")
|
||||
/**
|
||||
* Taint-propagating models for `StrTokenizer`.
|
||||
*/
|
||||
private class ApacheStrTokenizerModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;StrTokenizer;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;clone;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;next;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getContent;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;previous;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getTokenList;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getTokenArray;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;previousToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;StrTokenizer;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;clone;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;reset;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;reset;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;next;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getContent;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;previous;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getTokenList;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getTokenArray;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;previousToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;StringTokenizer;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;clone;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;reset;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;reset;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;next;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;getContent;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;previous;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;getTokenList;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;getTokenArray;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;previousToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable that constructs an Apache Commons `Str[ing]Lookup` from a map.
|
||||
* Taint-propagating models for `StrLookup`.
|
||||
*/
|
||||
private class ApacheStrLookupTaintingMethod extends TaintPreservingCallable {
|
||||
ApacheStrLookupTaintingMethod() {
|
||||
this.getSourceDeclaration().getDeclaringType() instanceof ApacheStrLookup and
|
||||
this.getName() = "mapLookup"
|
||||
or
|
||||
this.getDeclaringType() instanceof ApacheStringLookupFactory and
|
||||
this.getName() = "mapStringLookup"
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { arg = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable that looks up a value in a Apache Commons `Str[ing]Lookup` map.
|
||||
*/
|
||||
private class ApacheStrLookupTaintGetter extends TaintPreservingCallable {
|
||||
ApacheStrLookupTaintGetter() {
|
||||
this.getSourceDeclaration().getDeclaringType() instanceof ApacheStrLookup and
|
||||
this.getName() = "lookup"
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { arg = -1 }
|
||||
}
|
||||
|
||||
private class ApacheStrSubstitutor extends RefType {
|
||||
ApacheStrSubstitutor() {
|
||||
this.hasQualifiedName("org.apache.commons.lang3.text", "StrSubstitutor") or
|
||||
this.hasQualifiedName("org.apache.commons.text", "StringSubstitutor")
|
||||
private class ApacheStrLookupModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3.text;StrLookup;false;lookup;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrLookup;false;mapLookup;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text.lookup;StringLookup;true;lookup;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text.lookup;StringLookupFactory;false;mapStringLookup;;;Argument;ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable declared on Apache Commons `StrSubstitutor` that returns taint.
|
||||
* Taint-propagating models for `StrSubstitutor`.
|
||||
*/
|
||||
private class ApacheStrSubstitutorTaintGetter extends TaintPreservingCallable {
|
||||
ApacheStrSubstitutorTaintGetter() {
|
||||
this.getSourceDeclaration().getDeclaringType() instanceof ApacheStrSubstitutor and
|
||||
(
|
||||
this instanceof Constructor or
|
||||
this.getName() = "replace"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) {
|
||||
arg in [0, -1]
|
||||
or
|
||||
this.isStatic() and arg = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable declared on Apache Commons `StrSubstitutor` that transfers taint.
|
||||
*/
|
||||
private class ApacheStrSubstitutorTaintTransfer extends TaintPreservingCallable {
|
||||
ApacheStrSubstitutorTaintTransfer() {
|
||||
this.getSourceDeclaration().getDeclaringType() instanceof ApacheStrSubstitutor and
|
||||
this.getName() in ["replaceIn", "setVariableResolver"]
|
||||
}
|
||||
|
||||
override predicate transfersTaint(int src, int sink) {
|
||||
if this.getName() = "replaceIn" then (src = -1 and sink = 0) else (src = 0 and sink = -1)
|
||||
private class ApacheStrSubstitutorModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;StrSubstitutor;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(char[]);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(char[],int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.CharSequence);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.CharSequence,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(org.apache.commons.lang3.text.StrBuilder);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.StringBuffer);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.StringBuffer,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.String,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(org.apache.commons.lang3.text.StrBuilder,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;setVariableResolver;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(org.apache.commons.lang3.text.StrBuilder);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuffer,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(org.apache.commons.lang3.text.StrBuilder,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;StringSubstitutor;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(char[]);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(char[],int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.CharSequence);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.CharSequence,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.StringBuffer);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.StringBuffer,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.String,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(org.apache.commons.text.TextStringBuilder);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(org.apache.commons.text.TextStringBuilder,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;setVariableResolver;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuffer,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuilder,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(org.apache.commons.text.TextStringBuilder);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(org.apache.commons.text.TextStringBuilder,int,int);;Argument[-1];Argument[0];taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user