Merge pull request #2063 from kitkatt7/web-delete-needs-post
web: only delete channels, notes, keys and certs on POST
This commit is contained in:
9 files changed
+125
-11
No files matched your search
+5
-2
@@ -79,7 +79,8 @@ class CCertMod : public CModule {
|
||||
} else if (sPageName == "update") {
|
||||
CFile fPemFile(PemFile());
|
||||
|
||||
if (fPemFile.Open(O_WRONLY | O_TRUNC | O_CREAT)) {
|
||||
if (WebSock.IsPost() &&
|
||||
fPemFile.Open(O_WRONLY | O_TRUNC | O_CREAT)) {
|
||||
fPemFile.Write(WebSock.GetParam("cert", true, ""));
|
||||
fPemFile.Close();
|
||||
}
|
||||
@@ -87,7 +88,9 @@ class CCertMod : public CModule {
|
||||
WebSock.Redirect(GetWebPath());
|
||||
return true;
|
||||
} else if (sPageName == "delete") {
|
||||
CFile::Delete(PemFile());
|
||||
if (WebSock.IsPost()) {
|
||||
CFile::Delete(PemFile());
|
||||
}
|
||||
WebSock.Redirect(GetWebPath());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -375,7 +375,9 @@ class CSSLClientCertMod : public CModule {
|
||||
WebSock.Redirect(GetWebPath());
|
||||
return true;
|
||||
} else if (sPageName == "delete") {
|
||||
DelKey(*pUser, WebSock.GetParam("key", false));
|
||||
if (WebSock.IsPost()) {
|
||||
DelKey(*pUser, WebSock.GetParam("key"));
|
||||
}
|
||||
WebSock.Redirect(GetWebPath());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
<? INC Header.tmpl ?>
|
||||
|
||||
<? IF Cert ?>
|
||||
<? SETBLOCK DELLINK ?><a href="<? VAR URIPrefix TOP ?><? VAR ModPath ?>delete"><? FORMAT "here" "TRANSLATORS: this text is inserted into `click here` in the other string"?></a><? ENDSETBLOCK ?>
|
||||
<p><? FORMAT "You already have a certificate set, use the form below to overwrite the current certificate. Alternatively click {1} to delete your certificate." "DELLINK ESC=" "TRANSLATORS: {1} is `here`, translateable in the other string" ?></p>
|
||||
<form method="post" action="<? VAR URIPrefix TOP ?><? VAR ModPath ?>delete">
|
||||
<? INC _csrf_check.tmpl ?>
|
||||
<? SETBLOCK DELLINK ?><input type="submit" value="<? FORMAT "here" "TRANSLATORS: this text is inserted into `click here` in the other string"?>" /><? ENDSETBLOCK ?>
|
||||
<p><? FORMAT "You already have a certificate set, use the form below to overwrite the current certificate. Alternatively click {1} to delete your certificate." "DELLINK ESC=" "TRANSLATORS: {1} is `here`, translateable in the other string" ?></p>
|
||||
</form>
|
||||
<? ELSE ?>
|
||||
<p><? FORMAT "You do not have a certificate yet." ?></p>
|
||||
<? ENDIF ?>
|
||||
|
||||
@@ -33,7 +33,11 @@
|
||||
<tbody>
|
||||
<? LOOP KeyLoop ?>
|
||||
<tr class="<? IF __EVEN__ ?>evenrow<? ELSE ?>oddrow<? ENDIF ?>">
|
||||
<td>[<a href="<? VAR ModPath ?>delete?key=<? VAR Key ESC=URL,HTML ?>"><? FORMAT "del" ?></a>]</td>
|
||||
<td><form method="post" action="<? VAR URIPrefix TOP ?><? VAR ModPath TOP ?>delete">
|
||||
<? INC _csrf_check.tmpl ?>
|
||||
<input type="hidden" name="key" value="<? VAR Key ?>" />
|
||||
<input type="submit" value="<? FORMAT "del" ?>" />
|
||||
</form></td>
|
||||
<td><? VAR Key ?></td>
|
||||
</tr>
|
||||
<? ENDLOOP ?>
|
||||
|
||||
@@ -38,7 +38,11 @@
|
||||
<tbody>
|
||||
<? LOOP NotesLoop ?>
|
||||
<tr class="<? IF __EVEN__ ?>evenrow<? ELSE ?>oddrow<? ENDIF ?>">
|
||||
<td><a href="<? VAR URIPrefix TOP ?><? VAR ModPath TOP ?>delnote?key=<? VAR Key ESC=URL,HTML ?>"><img src="<? VAR URIPrefix TOP ?><? VAR ModFilesPath TOP ?>trash.gif" alt="<? FORMAT "[del]" ?>" /></a></td>
|
||||
<td><form method="post" action="<? VAR URIPrefix TOP ?><? VAR ModPath TOP ?>delnote">
|
||||
<? INC _csrf_check.tmpl ?>
|
||||
<input type="hidden" name="key" value="<? VAR Key ?>" />
|
||||
<input type="image" src="<? VAR URIPrefix TOP ?><? VAR ModFilesPath TOP ?>trash.gif" alt="<? FORMAT "[del]" ?>" />
|
||||
</form></td>
|
||||
<td><? VAR Key ?></td>
|
||||
<td><? VAR Note ?></td>
|
||||
</tr>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<? I18N znc-webadmin ?>
|
||||
<? INC Header.tmpl ?>
|
||||
|
||||
<div class="section">
|
||||
<h3><? FORMAT "Confirm Channel Deletion" ?></h3>
|
||||
<div class="sectionbg">
|
||||
<div class="sectionbody">
|
||||
<div class="subsection">
|
||||
<? FORMAT "Are you sure you want to delete channel “{3}” of network “{2}” of user “{1}”?" Username Network Channel ?>
|
||||
<form action="<? VAR URIPrefix TOP ?><? VAR ModPath TOP ?>delchan" method="post">
|
||||
<? INC _csrf_check.tmpl ?>
|
||||
<input type="hidden" name="user" value="<? VAR Username ?>" />
|
||||
<input type="hidden" name="network" value="<? VAR Network ?>" />
|
||||
<input type="hidden" name="name" value="<? VAR Channel ?>" />
|
||||
<div class="yesnobutton"><input type="submit" value="<? FORMAT "Yes" ?>"/></div>
|
||||
</form>
|
||||
<form action="<? VAR URIPrefix TOP ?><? VAR ModPath TOP ?>editnetwork" method="get">
|
||||
<input type="hidden" name="user" value="<? VAR Username ?>" />
|
||||
<input type="hidden" name="network" value="<? VAR Network ?>" />
|
||||
<div class="yesnobutton"><input type="submit" value="<? FORMAT "No" ?>"/></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<? INC Footer.tmpl ?>
|
||||
+3
-1
@@ -203,7 +203,9 @@ class CNotesMod : public CModule {
|
||||
|
||||
return true;
|
||||
} else if (sPageName == "delnote") {
|
||||
DelNote(WebSock.GetParam("key", false));
|
||||
if (WebSock.IsPost()) {
|
||||
DelNote(WebSock.GetParam("key"));
|
||||
}
|
||||
WebSock.Redirect(GetWebPath());
|
||||
return true;
|
||||
} else if (sPageName == "addnote") {
|
||||
|
||||
+16
-3
@@ -568,7 +568,7 @@ class CWebAdminMod : public CModule {
|
||||
}
|
||||
|
||||
if (pNetwork) {
|
||||
return DelChan(WebSock, pNetwork);
|
||||
return DelChan(WebSock, pNetwork, Tmpl);
|
||||
}
|
||||
|
||||
WebSock.PrintErrorPage(t_s("No such user or network"));
|
||||
@@ -1306,8 +1306,11 @@ class CWebAdminMod : public CModule {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DelChan(CWebSock& WebSock, CIRCNetwork* pNetwork) {
|
||||
CString sChan = WebSock.GetParam("name", false);
|
||||
bool DelChan(CWebSock& WebSock, CIRCNetwork* pNetwork, CTemplate& Tmpl) {
|
||||
CString sChan = WebSock.GetParam("name");
|
||||
if (sChan.empty() && !WebSock.IsPost()) {
|
||||
sChan = WebSock.GetParam("name", false);
|
||||
}
|
||||
|
||||
if (sChan.empty()) {
|
||||
WebSock.PrintErrorPage(
|
||||
@@ -1315,6 +1318,16 @@ class CWebAdminMod : public CModule {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!WebSock.IsPost()) {
|
||||
// Show the "Are you sure?" page:
|
||||
|
||||
Tmpl.SetFile("del_chan.tmpl");
|
||||
Tmpl["Username"] = pNetwork->GetUser()->GetUsername();
|
||||
Tmpl["Network"] = pNetwork->GetName();
|
||||
Tmpl["Channel"] = sChan;
|
||||
return true;
|
||||
}
|
||||
|
||||
pNetwork->DelChan(sChan);
|
||||
pNetwork->PutIRC("PART " + sChan);
|
||||
|
||||
|
||||
@@ -443,6 +443,62 @@ TEST_F(ZNCTest, ModuleCSRFOverride) {
|
||||
EXPECT_THAT(reply, HasSubstr("ipsum"));
|
||||
}
|
||||
|
||||
TEST_F(ZNCTest, WebDeleteNeedsPost) {
|
||||
int port = PickPortNumber();
|
||||
auto znc = Run();
|
||||
auto ircd = ConnectIRCd();
|
||||
auto client = LoginClient();
|
||||
client.Write(QStringLiteral("znc addport %1 all all").arg(port).toUtf8());
|
||||
client.ReadUntil(":Port added");
|
||||
client.Write("znc loadmod notes");
|
||||
client.ReadUntil("Loaded module");
|
||||
client.Write("PRIVMSG *notes :Add secretkey lorem");
|
||||
client.ReadUntil("Added note");
|
||||
|
||||
auto url = [&](const QString& path) {
|
||||
QNetworkRequest request(
|
||||
QUrl(QStringLiteral("http://127.0.0.1:%1%2").arg(port).arg(path)));
|
||||
request.setRawHeader("Authorization",
|
||||
"Basic " + QByteArray("user:hunter2").toBase64());
|
||||
return request;
|
||||
};
|
||||
HttpPost(url("/mods/global/webadmin/addchan"), {
|
||||
{"user", "user"},
|
||||
{"network", "test"},
|
||||
{"submitted", "1"},
|
||||
{"name", "#znc"},
|
||||
{"enabled", "1"},
|
||||
});
|
||||
const QString sEditNetwork =
|
||||
"/mods/global/webadmin/editnetwork?user=user&network=test";
|
||||
const std::string sChanRow = "name=\"channel\" value=\"#znc\"";
|
||||
EXPECT_THAT(HttpGet(url(sEditNetwork))->readAll().toStdString(),
|
||||
HasSubstr(sChanRow));
|
||||
|
||||
// A plain GET, e.g. from an <img> on another page, must not delete
|
||||
EXPECT_THAT(HttpGet(url("/mods/global/webadmin/"
|
||||
"delchan?user=user&network=test&name=%23znc"))
|
||||
->readAll()
|
||||
.toStdString(),
|
||||
HasSubstr("Confirm Channel Deletion"));
|
||||
EXPECT_THAT(HttpGet(url(sEditNetwork))->readAll().toStdString(),
|
||||
HasSubstr(sChanRow));
|
||||
HttpGet(url("/mods/user/notes/delnote?key=secretkey"));
|
||||
EXPECT_THAT(HttpGet(url("/mods/user/notes/"))->readAll().toStdString(),
|
||||
HasSubstr("secretkey"));
|
||||
|
||||
HttpPost(url("/mods/global/webadmin/delchan"), {
|
||||
{"user", "user"},
|
||||
{"network", "test"},
|
||||
{"name", "#znc"},
|
||||
});
|
||||
EXPECT_THAT(HttpGet(url(sEditNetwork))->readAll().toStdString(),
|
||||
Not(HasSubstr(sChanRow)));
|
||||
HttpPost(url("/mods/user/notes/delnote"), {{"key", "secretkey"}});
|
||||
EXPECT_THAT(HttpGet(url("/mods/user/notes/"))->readAll().toStdString(),
|
||||
Not(HasSubstr("secretkey")));
|
||||
}
|
||||
|
||||
class SaslModuleTest : public ZNCTest,
|
||||
public testing::WithParamInterface<
|
||||
std::pair<int, std::vector<std::string>>> {
|
||||
|
||||
Reference in new issue
Block a user