mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
JS: Port InsecureRandomness
This commit is contained in:
@@ -15,7 +15,37 @@ private import InsecureRandomnessCustomizations::InsecureRandomness as InsecureR
|
||||
/**
|
||||
* A taint tracking configuration for random values that are not cryptographically secure.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
module InsecureRandomnessConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
// stop propagation at the sinks to avoid double reporting
|
||||
isSink(node)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
InsecureRandomness::isAdditionalTaintStep(pred, succ)
|
||||
or
|
||||
// We want to make use of default taint steps but not the default taint sanitizers, as they
|
||||
// generally assume numbers aren't taintable. So we use a data-flow configuration that includes all
|
||||
// taint steps as additional flow steps.
|
||||
TaintTracking::defaultTaintStep(pred, succ)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint tracking for random values that are not cryptographically secure.
|
||||
*/
|
||||
module InsecureRandomnessFlow = DataFlow::Global<InsecureRandomnessConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use the `InsecureRandomnessFlow` module instead.
|
||||
*/
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "InsecureRandomness" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
import javascript
|
||||
import semmle.javascript.security.dataflow.InsecureRandomnessQuery
|
||||
import DataFlow::PathGraph
|
||||
import InsecureRandomnessFlow::PathGraph
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from InsecureRandomnessFlow::PathNode source, InsecureRandomnessFlow::PathNode sink
|
||||
where InsecureRandomnessFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"This uses a cryptographically insecure random number generated at $@ in a security context.",
|
||||
source.getNode(), source.getNode().toString()
|
||||
|
||||
@@ -1,176 +1,93 @@
|
||||
nodes
|
||||
| tst.js:2:20:2:32 | Math.random() |
|
||||
| tst.js:2:20:2:32 | Math.random() |
|
||||
| tst.js:2:20:2:32 | Math.random() |
|
||||
| tst.js:6:20:6:43 | "prefix ... andom() |
|
||||
| tst.js:6:20:6:43 | "prefix ... andom() |
|
||||
| tst.js:6:31:6:43 | Math.random() |
|
||||
| tst.js:6:31:6:43 | Math.random() |
|
||||
| tst.js:10:20:10:32 | Math.random() |
|
||||
| tst.js:10:20:10:32 | Math.random() |
|
||||
| tst.js:10:20:10:32 | Math.random() |
|
||||
| tst.js:19:9:19:36 | suffix |
|
||||
| tst.js:19:18:19:30 | Math.random() |
|
||||
| tst.js:19:18:19:30 | Math.random() |
|
||||
| tst.js:19:18:19:36 | Math.random() % 255 |
|
||||
| tst.js:20:20:20:36 | "prefix" + suffix |
|
||||
| tst.js:20:20:20:36 | "prefix" + suffix |
|
||||
| tst.js:20:31:20:36 | suffix |
|
||||
| tst.js:28:9:28:26 | pw |
|
||||
| tst.js:28:14:28:26 | Math.random() |
|
||||
| tst.js:28:14:28:26 | Math.random() |
|
||||
| tst.js:29:20:29:21 | pw |
|
||||
| tst.js:29:20:29:21 | pw |
|
||||
| tst.js:41:20:41:33 | !Math.random() |
|
||||
| tst.js:41:20:41:33 | !Math.random() |
|
||||
| tst.js:41:21:41:33 | Math.random() |
|
||||
| tst.js:41:21:41:33 | Math.random() |
|
||||
| tst.js:45:18:45:30 | Math.random() |
|
||||
| tst.js:45:18:45:30 | Math.random() |
|
||||
| tst.js:45:18:45:30 | Math.random() |
|
||||
| tst.js:50:16:50:28 | Math.random() |
|
||||
| tst.js:50:16:50:28 | Math.random() |
|
||||
| tst.js:50:16:50:28 | Math.random() |
|
||||
| tst.js:55:17:55:29 | Math.random() |
|
||||
| tst.js:55:17:55:29 | Math.random() |
|
||||
| tst.js:55:17:55:29 | Math.random() |
|
||||
| tst.js:61:17:61:34 | '' + Math.random() |
|
||||
| tst.js:61:17:61:34 | '' + Math.random() |
|
||||
| tst.js:61:22:61:34 | Math.random() |
|
||||
| tst.js:61:22:61:34 | Math.random() |
|
||||
| tst.js:66:18:66:42 | Math.fl ... ndom()) |
|
||||
| tst.js:66:18:66:42 | Math.fl ... ndom()) |
|
||||
| tst.js:66:29:66:41 | Math.random() |
|
||||
| tst.js:66:29:66:41 | Math.random() |
|
||||
| tst.js:71:9:71:48 | rand |
|
||||
| tst.js:71:16:71:48 | Math.fl ... 999999) |
|
||||
| tst.js:71:27:71:39 | Math.random() |
|
||||
| tst.js:71:27:71:39 | Math.random() |
|
||||
| tst.js:71:27:71:47 | Math.ra ... 9999999 |
|
||||
| tst.js:72:9:72:48 | concat |
|
||||
| tst.js:72:18:72:48 | ts.toSt ... tring() |
|
||||
| tst.js:72:34:72:37 | rand |
|
||||
| tst.js:72:34:72:48 | rand.toString() |
|
||||
| tst.js:73:23:73:28 | concat |
|
||||
| tst.js:73:23:73:28 | concat |
|
||||
| tst.js:77:16:77:21 | secret |
|
||||
| tst.js:77:16:77:21 | secret |
|
||||
| tst.js:80:7:80:19 | Math.random() |
|
||||
| tst.js:80:7:80:19 | Math.random() |
|
||||
| tst.js:84:19:84:31 | Math.random() |
|
||||
| tst.js:84:19:84:31 | Math.random() |
|
||||
| tst.js:84:19:84:31 | Math.random() |
|
||||
| tst.js:90:32:90:44 | Math.random() |
|
||||
| tst.js:90:32:90:44 | Math.random() |
|
||||
| tst.js:90:32:90:44 | Math.random() |
|
||||
| tst.js:95:33:95:45 | Math.random() |
|
||||
| tst.js:95:33:95:45 | Math.random() |
|
||||
| tst.js:95:33:95:45 | Math.random() |
|
||||
| tst.js:115:16:115:56 | Math.fl ... 00_000) |
|
||||
| tst.js:115:16:115:56 | Math.fl ... 00_000) |
|
||||
| tst.js:115:27:115:39 | Math.random() |
|
||||
| tst.js:115:27:115:39 | Math.random() |
|
||||
| tst.js:115:27:115:55 | Math.ra ... 000_000 |
|
||||
| tst.js:116:22:116:62 | Math.fl ... 00_000) |
|
||||
| tst.js:116:22:116:62 | Math.fl ... 00_000) |
|
||||
| tst.js:116:33:116:45 | Math.random() |
|
||||
| tst.js:116:33:116:45 | Math.random() |
|
||||
| tst.js:116:33:116:61 | Math.ra ... 000_000 |
|
||||
| tst.js:117:15:117:55 | Math.fl ... 00_000) |
|
||||
| tst.js:117:15:117:55 | Math.fl ... 00_000) |
|
||||
| tst.js:117:26:117:38 | Math.random() |
|
||||
| tst.js:117:26:117:38 | Math.random() |
|
||||
| tst.js:117:26:117:54 | Math.ra ... 000_000 |
|
||||
| tst.js:118:23:118:63 | Math.fl ... 00_000) |
|
||||
| tst.js:118:23:118:63 | Math.fl ... 00_000) |
|
||||
| tst.js:118:34:118:46 | Math.random() |
|
||||
| tst.js:118:34:118:46 | Math.random() |
|
||||
| tst.js:118:34:118:62 | Math.ra ... 000_000 |
|
||||
| tst.js:120:16:120:28 | Math.random() |
|
||||
| tst.js:120:16:120:28 | Math.random() |
|
||||
| tst.js:120:16:120:28 | Math.random() |
|
||||
| tst.js:121:18:121:30 | Math.random() |
|
||||
| tst.js:121:18:121:30 | Math.random() |
|
||||
| tst.js:121:18:121:30 | Math.random() |
|
||||
| tst.js:136:9:136:67 | password |
|
||||
| tst.js:136:9:136:67 | password |
|
||||
| tst.js:136:21:136:67 | chars[M ... ength)] |
|
||||
| tst.js:136:27:136:66 | Math.fl ... length) |
|
||||
| tst.js:136:38:136:50 | Math.random() |
|
||||
| tst.js:136:38:136:50 | Math.random() |
|
||||
| tst.js:136:38:136:65 | Math.ra ... .length |
|
||||
edges
|
||||
| tst.js:2:20:2:32 | Math.random() | tst.js:2:20:2:32 | Math.random() |
|
||||
| tst.js:6:31:6:43 | Math.random() | tst.js:6:20:6:43 | "prefix ... andom() |
|
||||
| tst.js:6:31:6:43 | Math.random() | tst.js:6:20:6:43 | "prefix ... andom() |
|
||||
| tst.js:6:31:6:43 | Math.random() | tst.js:6:20:6:43 | "prefix ... andom() |
|
||||
| tst.js:6:31:6:43 | Math.random() | tst.js:6:20:6:43 | "prefix ... andom() |
|
||||
| tst.js:10:20:10:32 | Math.random() | tst.js:10:20:10:32 | Math.random() |
|
||||
| tst.js:19:9:19:36 | suffix | tst.js:20:31:20:36 | suffix |
|
||||
| tst.js:19:18:19:30 | Math.random() | tst.js:19:18:19:36 | Math.random() % 255 |
|
||||
| tst.js:19:18:19:30 | Math.random() | tst.js:19:18:19:36 | Math.random() % 255 |
|
||||
| tst.js:19:18:19:36 | Math.random() % 255 | tst.js:19:9:19:36 | suffix |
|
||||
| tst.js:20:31:20:36 | suffix | tst.js:20:20:20:36 | "prefix" + suffix |
|
||||
| tst.js:20:31:20:36 | suffix | tst.js:20:20:20:36 | "prefix" + suffix |
|
||||
| tst.js:28:9:28:26 | pw | tst.js:29:20:29:21 | pw |
|
||||
| tst.js:28:9:28:26 | pw | tst.js:29:20:29:21 | pw |
|
||||
| tst.js:28:14:28:26 | Math.random() | tst.js:28:9:28:26 | pw |
|
||||
| tst.js:28:14:28:26 | Math.random() | tst.js:28:9:28:26 | pw |
|
||||
| tst.js:41:21:41:33 | Math.random() | tst.js:41:20:41:33 | !Math.random() |
|
||||
| tst.js:41:21:41:33 | Math.random() | tst.js:41:20:41:33 | !Math.random() |
|
||||
| tst.js:41:21:41:33 | Math.random() | tst.js:41:20:41:33 | !Math.random() |
|
||||
| tst.js:41:21:41:33 | Math.random() | tst.js:41:20:41:33 | !Math.random() |
|
||||
| tst.js:45:18:45:30 | Math.random() | tst.js:45:18:45:30 | Math.random() |
|
||||
| tst.js:50:16:50:28 | Math.random() | tst.js:50:16:50:28 | Math.random() |
|
||||
| tst.js:55:17:55:29 | Math.random() | tst.js:55:17:55:29 | Math.random() |
|
||||
| tst.js:61:22:61:34 | Math.random() | tst.js:61:17:61:34 | '' + Math.random() |
|
||||
| tst.js:61:22:61:34 | Math.random() | tst.js:61:17:61:34 | '' + Math.random() |
|
||||
| tst.js:61:22:61:34 | Math.random() | tst.js:61:17:61:34 | '' + Math.random() |
|
||||
| tst.js:61:22:61:34 | Math.random() | tst.js:61:17:61:34 | '' + Math.random() |
|
||||
| tst.js:66:29:66:41 | Math.random() | tst.js:66:18:66:42 | Math.fl ... ndom()) |
|
||||
| tst.js:66:29:66:41 | Math.random() | tst.js:66:18:66:42 | Math.fl ... ndom()) |
|
||||
| tst.js:66:29:66:41 | Math.random() | tst.js:66:18:66:42 | Math.fl ... ndom()) |
|
||||
| tst.js:66:29:66:41 | Math.random() | tst.js:66:18:66:42 | Math.fl ... ndom()) |
|
||||
| tst.js:71:9:71:48 | rand | tst.js:72:34:72:37 | rand |
|
||||
| tst.js:71:16:71:48 | Math.fl ... 999999) | tst.js:71:9:71:48 | rand |
|
||||
| tst.js:71:27:71:39 | Math.random() | tst.js:71:27:71:47 | Math.ra ... 9999999 |
|
||||
| tst.js:71:27:71:39 | Math.random() | tst.js:71:27:71:47 | Math.ra ... 9999999 |
|
||||
| tst.js:71:27:71:47 | Math.ra ... 9999999 | tst.js:71:16:71:48 | Math.fl ... 999999) |
|
||||
| tst.js:72:9:72:48 | concat | tst.js:73:23:73:28 | concat |
|
||||
| tst.js:72:9:72:48 | concat | tst.js:73:23:73:28 | concat |
|
||||
| tst.js:72:18:72:48 | ts.toSt ... tring() | tst.js:72:9:72:48 | concat |
|
||||
| tst.js:72:34:72:37 | rand | tst.js:72:34:72:48 | rand.toString() |
|
||||
| tst.js:72:34:72:48 | rand.toString() | tst.js:72:18:72:48 | ts.toSt ... tring() |
|
||||
| tst.js:77:16:77:21 | secret | tst.js:77:16:77:21 | secret |
|
||||
| tst.js:80:7:80:19 | Math.random() | tst.js:77:16:77:21 | secret |
|
||||
| tst.js:80:7:80:19 | Math.random() | tst.js:77:16:77:21 | secret |
|
||||
| tst.js:84:19:84:31 | Math.random() | tst.js:84:19:84:31 | Math.random() |
|
||||
| tst.js:90:32:90:44 | Math.random() | tst.js:90:32:90:44 | Math.random() |
|
||||
| tst.js:95:33:95:45 | Math.random() | tst.js:95:33:95:45 | Math.random() |
|
||||
| tst.js:115:27:115:39 | Math.random() | tst.js:115:27:115:55 | Math.ra ... 000_000 |
|
||||
| tst.js:115:27:115:39 | Math.random() | tst.js:115:27:115:55 | Math.ra ... 000_000 |
|
||||
| tst.js:115:27:115:55 | Math.ra ... 000_000 | tst.js:115:16:115:56 | Math.fl ... 00_000) |
|
||||
| tst.js:115:27:115:55 | Math.ra ... 000_000 | tst.js:115:16:115:56 | Math.fl ... 00_000) |
|
||||
| tst.js:116:33:116:45 | Math.random() | tst.js:116:33:116:61 | Math.ra ... 000_000 |
|
||||
| tst.js:116:33:116:45 | Math.random() | tst.js:116:33:116:61 | Math.ra ... 000_000 |
|
||||
| tst.js:116:33:116:61 | Math.ra ... 000_000 | tst.js:116:22:116:62 | Math.fl ... 00_000) |
|
||||
| tst.js:116:33:116:61 | Math.ra ... 000_000 | tst.js:116:22:116:62 | Math.fl ... 00_000) |
|
||||
| tst.js:117:26:117:38 | Math.random() | tst.js:117:26:117:54 | Math.ra ... 000_000 |
|
||||
| tst.js:117:26:117:38 | Math.random() | tst.js:117:26:117:54 | Math.ra ... 000_000 |
|
||||
| tst.js:117:26:117:54 | Math.ra ... 000_000 | tst.js:117:15:117:55 | Math.fl ... 00_000) |
|
||||
| tst.js:117:26:117:54 | Math.ra ... 000_000 | tst.js:117:15:117:55 | Math.fl ... 00_000) |
|
||||
| tst.js:118:34:118:46 | Math.random() | tst.js:118:34:118:62 | Math.ra ... 000_000 |
|
||||
| tst.js:118:34:118:46 | Math.random() | tst.js:118:34:118:62 | Math.ra ... 000_000 |
|
||||
| tst.js:118:34:118:62 | Math.ra ... 000_000 | tst.js:118:23:118:63 | Math.fl ... 00_000) |
|
||||
| tst.js:118:34:118:62 | Math.ra ... 000_000 | tst.js:118:23:118:63 | Math.fl ... 00_000) |
|
||||
| tst.js:120:16:120:28 | Math.random() | tst.js:120:16:120:28 | Math.random() |
|
||||
| tst.js:121:18:121:30 | Math.random() | tst.js:121:18:121:30 | Math.random() |
|
||||
| tst.js:136:21:136:67 | chars[M ... ength)] | tst.js:136:9:136:67 | password |
|
||||
| tst.js:136:21:136:67 | chars[M ... ength)] | tst.js:136:9:136:67 | password |
|
||||
| tst.js:136:27:136:66 | Math.fl ... length) | tst.js:136:21:136:67 | chars[M ... ength)] |
|
||||
| tst.js:136:38:136:50 | Math.random() | tst.js:136:38:136:65 | Math.ra ... .length |
|
||||
| tst.js:136:38:136:50 | Math.random() | tst.js:136:38:136:65 | Math.ra ... .length |
|
||||
| tst.js:136:38:136:65 | Math.ra ... .length | tst.js:136:27:136:66 | Math.fl ... length) |
|
||||
nodes
|
||||
| tst.js:2:20:2:32 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:6:20:6:43 | "prefix ... andom() | semmle.label | "prefix ... andom() |
|
||||
| tst.js:6:31:6:43 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:10:20:10:32 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:19:9:19:36 | suffix | semmle.label | suffix |
|
||||
| tst.js:19:18:19:30 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:19:18:19:36 | Math.random() % 255 | semmle.label | Math.random() % 255 |
|
||||
| tst.js:20:20:20:36 | "prefix" + suffix | semmle.label | "prefix" + suffix |
|
||||
| tst.js:20:31:20:36 | suffix | semmle.label | suffix |
|
||||
| tst.js:28:9:28:26 | pw | semmle.label | pw |
|
||||
| tst.js:28:14:28:26 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:29:20:29:21 | pw | semmle.label | pw |
|
||||
| tst.js:41:20:41:33 | !Math.random() | semmle.label | !Math.random() |
|
||||
| tst.js:41:21:41:33 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:45:18:45:30 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:50:16:50:28 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:55:17:55:29 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:61:17:61:34 | '' + Math.random() | semmle.label | '' + Math.random() |
|
||||
| tst.js:61:22:61:34 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:66:18:66:42 | Math.fl ... ndom()) | semmle.label | Math.fl ... ndom()) |
|
||||
| tst.js:66:29:66:41 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:71:9:71:48 | rand | semmle.label | rand |
|
||||
| tst.js:71:16:71:48 | Math.fl ... 999999) | semmle.label | Math.fl ... 999999) |
|
||||
| tst.js:71:27:71:39 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:71:27:71:47 | Math.ra ... 9999999 | semmle.label | Math.ra ... 9999999 |
|
||||
| tst.js:72:9:72:48 | concat | semmle.label | concat |
|
||||
| tst.js:72:18:72:48 | ts.toSt ... tring() | semmle.label | ts.toSt ... tring() |
|
||||
| tst.js:72:34:72:37 | rand | semmle.label | rand |
|
||||
| tst.js:72:34:72:48 | rand.toString() | semmle.label | rand.toString() |
|
||||
| tst.js:73:23:73:28 | concat | semmle.label | concat |
|
||||
| tst.js:77:16:77:21 | secret | semmle.label | secret |
|
||||
| tst.js:77:16:77:21 | secret | semmle.label | secret |
|
||||
| tst.js:80:7:80:19 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:84:19:84:31 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:90:32:90:44 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:95:33:95:45 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:115:16:115:56 | Math.fl ... 00_000) | semmle.label | Math.fl ... 00_000) |
|
||||
| tst.js:115:27:115:39 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:115:27:115:55 | Math.ra ... 000_000 | semmle.label | Math.ra ... 000_000 |
|
||||
| tst.js:116:22:116:62 | Math.fl ... 00_000) | semmle.label | Math.fl ... 00_000) |
|
||||
| tst.js:116:33:116:45 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:116:33:116:61 | Math.ra ... 000_000 | semmle.label | Math.ra ... 000_000 |
|
||||
| tst.js:117:15:117:55 | Math.fl ... 00_000) | semmle.label | Math.fl ... 00_000) |
|
||||
| tst.js:117:26:117:38 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:117:26:117:54 | Math.ra ... 000_000 | semmle.label | Math.ra ... 000_000 |
|
||||
| tst.js:118:23:118:63 | Math.fl ... 00_000) | semmle.label | Math.fl ... 00_000) |
|
||||
| tst.js:118:34:118:46 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:118:34:118:62 | Math.ra ... 000_000 | semmle.label | Math.ra ... 000_000 |
|
||||
| tst.js:120:16:120:28 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:121:18:121:30 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:136:9:136:67 | password | semmle.label | password |
|
||||
| tst.js:136:21:136:67 | chars[M ... ength)] | semmle.label | chars[M ... ength)] |
|
||||
| tst.js:136:27:136:66 | Math.fl ... length) | semmle.label | Math.fl ... length) |
|
||||
| tst.js:136:38:136:50 | Math.random() | semmle.label | Math.random() |
|
||||
| tst.js:136:38:136:65 | Math.ra ... .length | semmle.label | Math.ra ... .length |
|
||||
subpaths
|
||||
#select
|
||||
| tst.js:2:20:2:32 | Math.random() | tst.js:2:20:2:32 | Math.random() | tst.js:2:20:2:32 | Math.random() | This uses a cryptographically insecure random number generated at $@ in a security context. | tst.js:2:20:2:32 | Math.random() | Math.random() |
|
||||
| tst.js:6:20:6:43 | "prefix ... andom() | tst.js:6:31:6:43 | Math.random() | tst.js:6:20:6:43 | "prefix ... andom() | This uses a cryptographically insecure random number generated at $@ in a security context. | tst.js:6:31:6:43 | Math.random() | Math.random() |
|
||||
|
||||
Reference in New Issue
Block a user