Browse Source

implement post validation

main
ghost 12 months ago
parent
commit
d4e450b6af
  1. 9
      .env
  2. 4
      config/services.yaml
  3. 8
      public/css/default.css
  4. 3
      src/Controller/ModuleController.php
  5. 133
      src/Controller/RoomController.php
  6. 5
      templates/default/module/post.html.twig
  7. 2
      templates/default/room/index.html.twig

9
.env

@ -23,6 +23,10 @@ APP_VERSION=1.0.0
APP_NAME=KevaChat APP_NAME=KevaChat
# Connect memcached
APP_MEMCACHED_HOST=127.0.0.1
APP_MEMCACHED_PORT=11211
# Connect kevacoin # Connect kevacoin
APP_KEVACOIN_PROTOCOL=http APP_KEVACOIN_PROTOCOL=http
@ -59,5 +63,8 @@ APP_ADD_POST_REMOTE_IP_DELAY=60
# Skip access limits for following IPs separated by | # Skip access limits for following IPs separated by |
APP_ADD_POST_REMOTE_IP_MODERATORS= APP_ADD_POST_REMOTE_IP_MODERATORS=
# Skip access limits for banned IPs separated by |
APP_ADD_POST_REMOTE_IP_DENIED=
# Post content rules (for kevacoin value) # Post content rules (for kevacoin value)
APP_ADD_POST_VALUE_REGEX=/[\w]{2,3072}/ APP_ADD_POST_VALUE_REGEX=/^[\w\s]{2,3072}$/ui

4
config/services.yaml

@ -6,7 +6,8 @@
parameters: parameters:
app.version: '%env(APP_VERSION)%' app.version: '%env(APP_VERSION)%'
app.name: '%env(APP_NAME)%' app.name: '%env(APP_NAME)%'
app.memcached.host: '%env(APP_MEMCACHED_HOST)%'
app.memcached.port: '%env(APP_MEMCACHED_PORT)%'
app.kevacoin.protocol: '%env(APP_KEVACOIN_PROTOCOL)%' app.kevacoin.protocol: '%env(APP_KEVACOIN_PROTOCOL)%'
app.kevacoin.host: '%env(APP_KEVACOIN_HOST)%' app.kevacoin.host: '%env(APP_KEVACOIN_HOST)%'
app.kevacoin.port: '%env(APP_KEVACOIN_PORT)%' app.kevacoin.port: '%env(APP_KEVACOIN_PORT)%'
@ -22,6 +23,7 @@ parameters:
app.add.post.remote.ip.regex: '%env(APP_ADD_POST_REMOTE_IP_REGEX)%' app.add.post.remote.ip.regex: '%env(APP_ADD_POST_REMOTE_IP_REGEX)%'
app.add.post.remote.ip.delay: '%env(APP_ADD_POST_REMOTE_IP_DELAY)%' app.add.post.remote.ip.delay: '%env(APP_ADD_POST_REMOTE_IP_DELAY)%'
app.add.post.remote.ip.moderators: '%env(APP_ADD_POST_REMOTE_IP_MODERATORS)%' app.add.post.remote.ip.moderators: '%env(APP_ADD_POST_REMOTE_IP_MODERATORS)%'
app.add.post.remote.ip.denied: '%env(APP_ADD_POST_REMOTE_IP_DENIED)%'
app.add.post.value.regex: '%env(APP_ADD_POST_VALUE_REGEX)%' app.add.post.value.regex: '%env(APP_ADD_POST_VALUE_REGEX)%'
services: services:

8
public/css/default.css

@ -146,4 +146,12 @@ footer > form > button
cursor: pointer; cursor: pointer;
float: right; float: right;
padding: 2px 8px; padding: 2px 8px;
}
footer > form > output
{
color: #ff6363;
display: block;
font-weight: bolder;
margin-bottom: 16px;
} }

3
src/Controller/ModuleController.php

@ -156,8 +156,9 @@ class ModuleController extends AbstractController
[ [
'enabled' => in_array($request->get('namespace'), $public), 'enabled' => in_array($request->get('namespace'), $public),
'namespace' => $request->get('namespace'), 'namespace' => $request->get('namespace'),
'message' => $message,
'user' => $request->get('user'), 'user' => $request->get('user'),
'error' => $request->get('error'),
'message' => $message,
'ip' => $request->getClientIp() 'ip' => $request->getClientIp()
] ]
); );

133
src/Controller/RoomController.php

@ -3,6 +3,7 @@
namespace App\Controller; namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@ -165,9 +166,27 @@ class RoomController extends AbstractController
] ]
)] )]
public function post( public function post(
Request $request Request $request,
TranslatorInterface $translator
): Response ): Response
{ {
// Connect memcached
$memcached = new \Memcached();
$memcached->addServer(
$this->getParameter('app.memcached.host'),
$this->getParameter('app.memcached.port')
);
$memory = [
'app.add.post.remote.ip.delay' => md5(
sprintf(
'kevachat.app.add.post.remote.ip.delay:%s.%s',
$this->getParameter('app.name'),
$request->getClientIp(),
),
),
];
// Connect kevacoin // Connect kevacoin
$client = new \Kevachat\Kevacoin\Client( $client = new \Kevachat\Kevacoin\Client(
$this->getParameter('app.kevacoin.protocol'), $this->getParameter('app.kevacoin.protocol'),
@ -188,13 +207,27 @@ class RoomController extends AbstractController
// Check namespace exist for this wallet // Check namespace exist for this wallet
if (!in_array($request->get('namespace'), $namespaces)) if (!in_array($request->get('namespace'), $namespaces))
{ {
exit('Namespace not related with this node!'); return $this->redirectToRoute(
'room_namespace',
[
'namespace' => $request->get('namespace'),
'message' => $request->get('message'),
'error' => $translator->trans('Namespace not related with this node!')
]
);
} }
// Check namespace writable // Check namespace writable
if (!in_array($request->get('namespace'), (array) explode('|', $this->getParameter('app.kevacoin.room.namespaces')))) if (!in_array($request->get('namespace'), (array) explode('|', $this->getParameter('app.kevacoin.room.namespaces'))))
{ {
exit('Namespace not listed in settings!'); return $this->redirectToRoute(
'room_namespace',
[
'namespace' => $request->get('namespace'),
'message' => $request->get('message'),
'error' => $translator->trans('Namespace not listed in settings!')
]
);
} }
// Validate access to the room namespace // Validate access to the room namespace
@ -202,6 +235,7 @@ class RoomController extends AbstractController
( (
// Ignore this rule for is moderators // Ignore this rule for is moderators
!in_array( !in_array(
$request->getClientIp(),
(array) explode('|', $this->getParameter('app.add.post.remote.ip.moderators')) (array) explode('|', $this->getParameter('app.add.post.remote.ip.moderators'))
) && ) &&
@ -212,22 +246,107 @@ class RoomController extends AbstractController
) )
) )
{ {
exit('Namespace for read only!'); return $this->redirectToRoute(
'room_namespace',
[
'namespace' => $request->get('namespace'),
'message' => $request->get('message'),
'error' => $translator->trans('Namespace for read only!')
]
);
}
// Deny requests from banned remote hosts
if (in_array($request->getClientIp(), (array) explode('|', $this->getParameter('app.add.post.remote.ip.denied'))))
{
return $this->redirectToRoute(
'room_namespace',
[
'namespace' => $request->get('namespace'),
'message' => $request->get('message'),
'error' => $translator->trans('Access denied for this IP!')
]
);
} }
// Validate remote IP regex // Validate remote IP regex
if (!preg_match($this->getParameter('app.add.post.remote.ip.regex'), $request->getClientIp()))
{
return $this->redirectToRoute(
'room_namespace',
[
'namespace' => $request->get('namespace'),
'message' => $request->get('message'),
'error' => $translator->trans('Access not allowed for this IP!')
]
);
}
// Validate remote IP limits // Validate message regex
if (!preg_match($this->getParameter('app.add.post.value.regex'), $request->get('message')))
{
return $this->redirectToRoute(
'room_namespace',
[
'namespace' => $request->get('namespace'),
'message' => $request->get('message'),
'error' => sprintf(
$translator->trans('Message does not match node requirements: %s'),
$this->getParameter('app.add.post.value.regex')
)
]
);
}
// Validate funds /// Validate remote IP limits
if ($delay = (int) $memcached->get($memory['app.add.post.remote.ip.delay']))
{
// Error
return $this->redirectToRoute(
'room_namespace',
[
'namespace' => $request->get('namespace'),
'message' => $request->get('message'),
'error' => sprintf(
$translator->trans('Please wait for %s seconds before post new message!'),
(int) $this->getParameter('app.add.post.remote.ip.delay') - (time() - $delay)
)
]
);
}
/// Validate funds available yet
if (1 > $client->getBalance())
{
return $this->redirectToRoute(
'room_namespace',
[
'namespace' => $request->get('namespace'),
'message' => $request->get('message'),
'error' => sprintf(
$translator->trans('Insufficient funds, wallet: %s'),
$this->getParameter('app.kevacoin.mine.address')
)
]
);
}
// @TODO Send message to DHT // @TODO Send message to DHT
// Register event time
$memcached->set(
$memory['app.add.post.remote.ip.delay'],
time(),
(int) $this->getParameter('app.add.post.remote.ip.delay')
);
// Redirect back to room // Redirect back to room
return $this->redirectToRoute( return $this->redirectToRoute(
'room_namespace', 'room_namespace',
[ [
'namespace' => $request->get('namespace') 'namespace' => $request->get('namespace'),
'error' => null,
'message' => null
] ]
); );
} }

5
templates/default/module/post.html.twig

@ -1,6 +1,9 @@
{% if enabled %} {% if enabled %}
<form name="post" action="{{ path('room_post', { namespace : namespace }) }}" method="post"> <form name="post" action="{{ path('room_post', { namespace : namespace }) }}" method="post">
<textarea name="message" placeholder="{{ 'enter your message...' | trans }}">{{ message }}</textarea> {% if error %}
<output name="error" for="form-post-message">{{ error }}</output>
{% endif %}
<textarea name="message" id="form-post-message" placeholder="{{ 'enter your message...' | trans }}">{{ message }}</textarea>
{% if user == 'anonymous' or user != 'ip' %} {% if user == 'anonymous' or user != 'ip' %}
<input type="radio" name="user" value="anonymous" id="form-post-user-anonymous" checked="checked" /> <input type="radio" name="user" value="anonymous" id="form-post-user-anonymous" checked="checked" />
{% else %} {% else %}

2
templates/default/room/index.html.twig

@ -24,7 +24,7 @@
</strong> </strong>
{% endif %} {% endif %}
&bull; &bull;
<a href="#{{ post.txid }}" title="{{ 'time:' | trans }} {{ post.transaction.time }} / {{ 'confirmations:' | trans }} {{ post.transaction.confirmations }}">{{ post.transaction.timestamp | format_ago }}</a> <a href="{{ path('room_namespace', { namespace : request.get('namespace') }) }}#{{ post.txid }}" title="{{ 'time:' | trans }} {{ post.transaction.time }} / {{ 'confirmations:' | trans }} {{ post.transaction.confirmations }}">{{ post.transaction.timestamp | format_ago }}</a>
&bull; &bull;
<a href="{{ path('room_namespace', { namespace : request.get('namespace'), txid : post.txid }) }}#{{ post.txid }}">{{ 'quote' | trans }}</a> <a href="{{ path('room_namespace', { namespace : request.get('namespace'), txid : post.txid }) }}#{{ post.txid }}">{{ 'quote' | trans }}</a>
<p> <p>

Loading…
Cancel
Save