Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch 70 #2222

Merged
merged 6 commits into from Apr 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 34 additions & 12 deletions javascript-source/commands/customCommands.js
Expand Up @@ -771,20 +771,42 @@
* @param {sub} subcommand
* @returns 0 = good, 1 = command perm bad, 2 = subcommand perm bad
*/
function permCom(username, command, subcommand) {
function permCom(username, command, subcommand, tags) {
var commandGroup, allowed;
if (subcommand === '') {
if ($.getCommandGroup(command) >= $.getUserGroupId(username)) {
return 0;
} else {
return 1;
}
commandGroup = $.getCommandGroup(command);
} else {
if ($.getSubcommandGroup(command, subcommand) >= $.getUserGroupId(username)) {
return 0;
} else {
return 2;
}
}
commandGroup = $.getSubcommandGroup(command, subcommand);
}

switch(commandGroup) {
case 0:
allowed = $.isCaster(username);
break;
case 1:
allowed = $.isAdmin(username);
break;
case 2:
allowed = $.isModv3(username, tags);
break;
case 3:
allowed = $.isSubv3(username, tags) || $.isModv3(username, tags);
break;
case 4:
allowed = $.isDonator(username) || $.isModv3(username, tags);
break;
case 5:
allowed = $.isVIP(username, tags) || $.isModv3(username, tags);
break;
case 6:
allowed = $.isReg(username) || $.isModv3(username, tags);
break;
default:
allowed = true;
break;
}

return allowed ? 0 : (subcommand === '' ? 1 : 2);
}

/*
Expand Down
4 changes: 2 additions & 2 deletions javascript-source/core/commandRegister.js
Expand Up @@ -228,7 +228,7 @@
} else if (commands[command].groupId == 4) {
group = 'Donator';
} else if (commands[command].groupId == 5) {
group = 'Hoster';
group = 'VIP';
} else if (commands[command].groupId == 6) {
group = 'Regular';
} else if (commands[command].groupId == 7) {
Expand Down Expand Up @@ -278,7 +278,7 @@
} else if (commands[command].subcommands[subcommand].groupId == 4) {
group = 'Donator';
} else if (commands[command].subcommands[subcommand].groupId == 5) {
group = 'Hoster';
group = 'VIP';
} else if (commands[command].subcommands[subcommand].groupId == 6) {
group = 'Regular';
} else if (commands[command].subcommands[subcommand].groupId == 7) {
Expand Down
15 changes: 15 additions & 0 deletions javascript-source/core/misc.js
Expand Up @@ -142,6 +142,20 @@
}
}

function equalsIgnoreCase(str1, str2) {
try {
return str1.equalsIgnoreCase(str2);
} catch (e) {
try {
return str1.toLowerCase() == str2.toLowerCase();
} catch (e) {
return false;
}
}

return false;
}

/**
* @function say
* @export $
Expand Down Expand Up @@ -748,4 +762,5 @@
$.getMessageWrites = getMessageWrites;
$.sayWithTimeout = sayWithTimeout;
$.paginateArrayDiscord = paginateArrayDiscord;
$.equalsIgnoreCase = equalsIgnoreCase;
})();
6 changes: 3 additions & 3 deletions javascript-source/core/permissions.js
Expand Up @@ -151,7 +151,7 @@
var idx = -1;

for (var i = 0; i < list.length; i++) {
if (list[i] !== undefined && list[i].equalsIgnoreCase(value)) {
if (list[i] !== undefined && $.equalsIgnoreCase(list[i], value)) {
idx = i;
break;
}
Expand Down Expand Up @@ -228,7 +228,7 @@
* @returns {boolean}
*/
function isModv3(username, tags) {
return (tags != null && tags != '{}' && tags.get('user-type').length() > 0) || isModeratorCache(username.toLowerCase());
return (tags != null && tags != '{}' && tags.get('user-type').length() > 0) || isModeratorCache(username.toLowerCase()) || isOwner(username);
}

/**
Expand All @@ -249,7 +249,7 @@
* @returns {boolean}
*/
function isSubv3(username, tags) {
return (tags != null && tags != '{}' && tags.get('subscriber').equals('1'));
return (tags != null && tags != '{}' && tags.get('subscriber').equals('1')) || isSub(username);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion javascript-source/init.js
Expand Up @@ -499,7 +499,7 @@
} else

// Check the command permission.
if ($.permCom(sender, command, subCommand) !== 0) {
if ($.permCom(sender, command, subCommand, event.getTags()) !== 0) {
$.sayWithTimeout($.whisperPrefix(sender) + $.lang.get('cmd.perm.404', (!$.subCommandExists(command, subCommand) ? $.getCommandGroupName(command) : $.getSubCommandGroupName(command, subCommand))), $.getIniDbBoolean('settings', 'permComMsgEnabled', false));
consoleDebug('Command !' + command + ' was not sent due to the user not having permission for it.');
return;
Expand Down
3 changes: 3 additions & 0 deletions source/com/gmt2001/httpwsserver/HTTPWSServer.java
Expand Up @@ -56,6 +56,8 @@ public final class HTTPWSServer {
*/
private Channel ch;

public boolean sslEnabled = false;

/**
* Gets the server instance.
*
Expand Down Expand Up @@ -112,6 +114,7 @@ private HTTPWSServer(String ipOrHostname, int port, boolean useHttps, String ssl
tmf.init(ks);

sslCtx = SslContextBuilder.forServer(kmf).trustManager(tmf).build();
sslEnabled = true;
}
} else {
sslCtx = null;
Expand Down
7 changes: 4 additions & 3 deletions source/com/gmt2001/httpwsserver/HTTPWSServerInitializer.java
Expand Up @@ -23,6 +23,7 @@
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.ssl.OptionalSslHandler;
import io.netty.handler.ssl.SslContext;

/**
Expand Down Expand Up @@ -58,14 +59,14 @@ protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();

if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
pipeline.addLast(new HttpOptionalSslHandler(sslCtx));
}

pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new WebSocketServerCompressionHandler());
pipeline.addLast(new WebSocketServerProtocolHandler("/ws", null, true, 65536, false, true));
pipeline.addLast(new HttpServerPageHandler());
pipeline.addLast(new WebSocketFrameHandler());
pipeline.addLast("pagehandler", new HttpServerPageHandler());
pipeline.addLast("wshandler", new WebSocketFrameHandler());
}
}
44 changes: 44 additions & 0 deletions source/com/gmt2001/httpwsserver/HttpOptionalSslHandler.java
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2016-2019 phantombot.tv
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.gmt2001.httpwsserver;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.ssl.OptionalSslHandler;
import io.netty.handler.ssl.SslContext;

/**
* Detects Non-SSL HTTP connections and activates the SSL Redirect handler, when SSL is enabled
*
* @author gmt2001
*/
public class HttpOptionalSslHandler extends OptionalSslHandler {

/**
* Default Constructor
*/
HttpOptionalSslHandler(SslContext sslContext) {
super(sslContext);
}

@Override
protected ChannelHandler newNonSslHandler(ChannelHandlerContext context) {
context.pipeline().replace("pagehandler", "httpsslredirect", new HttpSslRedirectHandler());
context.pipeline().replace("wshandler", "wssslerror", new WsSslErrorHandler());
return null;
}
}
83 changes: 83 additions & 0 deletions source/com/gmt2001/httpwsserver/HttpSslRedirectHandler.java
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2016-2019 phantombot.tv
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.gmt2001.httpwsserver;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.sqlite.SQLiteConfig;

/**
* Redirects HTTP requests to HTTPS, when SSL is enabled
*
* @author gmt2001
*/
public class HttpSslRedirectHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

/**
* Default Constructor
*/
HttpSslRedirectHandler() {
super();
}

/**
* Redirects non-SSL requests to SSL
*
* @param ctx The {@link ChannelHandlerContext} of the session
* @param req The {@link FullHttpRequest} containing the request
* @throws Exception Passes any thrown exceptions up the stack
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
if (!req.decoderResult().isSuccess()) {
HttpServerPageHandler.sendHttpResponse(ctx, req, HttpServerPageHandler.prepareHttpResponse(HttpResponseStatus.BAD_REQUEST, null, null));
return;
}

String host = req.headers().get(HttpHeaderNames.HOST);

if (host != null && !host.isBlank()) {
String uri = "https://" + host + req.uri();

com.gmt2001.Console.debug.println("301: " + uri);

FullHttpResponse res = HttpServerPageHandler.prepareHttpResponse(HttpResponseStatus.MOVED_PERMANENTLY, null, null);

res.headers().set(HttpHeaderNames.LOCATION, uri);

HttpServerPageHandler.sendHttpResponse(ctx, req, res);
} else {
HttpServerPageHandler.sendHttpResponse(ctx, req, HttpServerPageHandler.prepareHttpResponse(HttpResponseStatus.FORBIDDEN, "HTTPS Required".getBytes(), null));
}
}

/**
* Handles exceptions that are thrown up the stack
*
* @param ctx The {@link ChannelHandlerContext} of the session
* @param cause The exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
com.gmt2001.Console.debug.printOrLogStackTrace(cause);
ctx.close();
}
}
84 changes: 84 additions & 0 deletions source/com/gmt2001/httpwsserver/WsSslErrorHandler.java
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2016-2019 phantombot.tv
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.gmt2001.httpwsserver;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler.HandshakeComplete;
import org.json.JSONStringer;

/**
* Processes WebSocket frames and passes successful ones to the appropriate registered final handler
*
* @author gmt2001
*/
public class WsSslErrorHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

WsSslErrorHandler() {
super();
}

/**
* Handles incoming WebSocket frames and passes them to the appropriate {@link WsFrameHandler}
*
* @param ctx The {@link ChannelHandlerContext} of the session
* @param req The {@link WebSocketFrame} containing the request frame
* @throws Exception Passes any thrown exceptions up the stack
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {

}

/**
* Captures {@link HandshakeComplete} events and saves the {@link WsFrameHandler} URI to the session
*
* If a handler is not available for the requested path, then {@code 404 NOT FOUND} is sent back to the client using JSON:API format
*
* @param ctx The {@link ChannelHandlerContext} of the session
* @param evt The event object
* @throws Exception Passes any thrown exceptions up the stack
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof HandshakeComplete) {
JSONStringer jsonObject = new JSONStringer();
jsonObject.object().key("errors").array().object()
.key("status").value("403")
.key("title").value("Forbidden")
.key("detail").value("WSS Required")
.endObject().endArray().endObject();

ctx.channel().writeAndFlush(new TextWebSocketFrame(jsonObject.toString()));
ctx.close();
}
}

/**
* Handles exceptions that are thrown up the stack
*
* @param ctx The {@link ChannelHandlerContext} of the session
* @param cause The exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
com.gmt2001.Console.debug.printOrLogStackTrace(cause);
ctx.close();
}
}