Ejemplo n.º 1
0
 def hasChildren(self, idx):
     item = self.itemFromIndex(idx)
     if not item:
         return True
     node = item.data()
     if node in self._fetched:
         return QStandardItemModel.hasChildren(self, idx)
     return True
Ejemplo n.º 2
0
 def hasChildren(self, idx):
     item = self.itemFromIndex(idx)
     if not item:
         return True
     node = item.data()
     if node in self._fetched:
         return QStandardItemModel.hasChildren(self, idx)
     return True
Ejemplo n.º 3
0
class OutboundSocksPanel(QWidget):
    def __init__(self):
        super().__init__()
        self.outboundSocksJSONFile = {
                                        "servers": [{
                                            "address": "127.0.0.1",
                                            "port": 1080,
                                            "users": [{
                                                    "user": "******",
                                                    "pass": "******",
                                                    "level": 0
                                                }]
                                            }]
                                      }
        self.translate = QCoreApplication.translate

        self.labeloutSocks = (self.translate("OutboundSocksPanel", "Address"), 
                              self.translate("OutboundSocksPanel", "Port"), 
                              self.translate("OutboundSocksPanel", "Level"))
    
    def createOutboundSocksSettingPanel(self):
        labelAddress = QLabel(
            self.translate("OutboundSocksPanel", "Server Address: "), self)
        self.lineEditOutboundSocksAddress = QLineEdit()
        labelPort    = QLabel(
            self.translate("OutboundSocksPanel", "Port: "), self)
        self.spinBoxOutboundSocksPort     = QSpinBox()
    
        labelUserName = QLabel(
            self.translate("OutboundSocksPanel", "User: "******"OutboundSocksPanel", "Password: "******"OutboundSocksPanel", "User Level: "))
        self.spinBoxOutboundSocksuerLevel = QSpinBox()
        self.spinBoxOutboundSocksuerLevel.setRange(0, 65535)
        self.spinBoxOutboundSocksuerLevel.setValue(0)
        self.spinBoxOutboundSocksuerLevel.setDisabled(True)
        
        hboxuserLevel = QHBoxLayout()
        hboxuserLevel.addWidget(labelLevel)
        hboxuserLevel.addWidget(self.spinBoxOutboundSocksuerLevel)
        hboxuserLevel.addStretch()
        
        self.btnOutboundSocksClear  = QPushButton(
            self.translate("OutboundSocksPanel", "Clear"))
        self.btnOutboundSocksChange = QPushButton(
            self.translate("OutboundSocksPanel", "Modify"))
        self.btnOutboundSocksAdd    = QPushButton(
            self.translate("OutboundSocksPanel", "Add"))
        self.btnOutboundSocksDelete = QPushButton(
            self.translate("OutboundSocksPanel", "Delete"))
        
        self.spinBoxOutboundSocksPort.setRange(0, 65535)
        self.spinBoxOutboundSocksPort.setValue(1080)
        
        hboxAdress = QHBoxLayout()
        hboxAdress.addWidget(labelAddress)
        hboxAdress.addWidget(self.lineEditOutboundSocksAddress)
        hboxAdress.addWidget(labelPort)
        hboxAdress.addWidget(self.spinBoxOutboundSocksPort)
        hboxAdress.addStretch()
        
        hboxUser = QHBoxLayout()
        hboxUser.addWidget(labelUserName)
        hboxUser.addWidget(self.lineEditOutboundSocksUserName)
        hboxUser.addWidget(labelPassowrd)
        hboxUser.addWidget(self.lineEditOutboundSocksPassword)
        hboxUser.addStretch()
        
        vboxBtnUser = QVBoxLayout()
        vboxBtnUser.addStretch()
        vboxBtnUser.addWidget(self.btnOutboundSocksAdd)
        vboxBtnUser.addWidget(self.btnOutboundSocksClear)
        vboxBtnUser.addWidget(self.btnOutboundSocksChange)
        vboxBtnUser.addWidget(self.btnOutboundSocksDelete)
        
        self.treeViewoutSocksAddress = treeViewoutSocksAddress = QTreeView() 
        treeViewoutSocksAddress.setSelectionMode(QAbstractItemView.SingleSelection)
        treeViewoutSocksAddress.setSelectionBehavior(QAbstractItemView.SelectRows)
        treeViewoutSocksAddress.setUniformRowHeights(True)
        treeViewoutSocksAddress.setEditTriggers(QAbstractItemView.NoEditTriggers)
        
        self.treeViewoutSocksAddressMode = QStandardItemModel()
        self.treeViewoutSocksAddressMode.setHorizontalHeaderLabels(self.labeloutSocks)
        self.treeViewoutSocksAddress.setModel(self.treeViewoutSocksAddressMode)

        hboxtreeView = QHBoxLayout()
        hboxtreeView.addWidget(self.treeViewoutSocksAddress)
        hboxtreeView.addLayout(vboxBtnUser)
        
        vboxOutboundSocks = QVBoxLayout()
        vboxOutboundSocks.addLayout(hboxAdress)
        vboxOutboundSocks.addLayout(hboxUser)
        vboxOutboundSocks.addLayout(hboxuserLevel)
        vboxOutboundSocks.addLayout(hboxtreeView)

        groupBoxOutboundSocksPanel = QGroupBox(
            self.translate("OutboundSocksPanel", "Socks"), self)
        groupBoxOutboundSocksPanel.setLayout(vboxOutboundSocks)
        
        if (v2rayshellDebug):
            self.__btnDebug = QPushButton("__DebugTest", self)
            vboxOutboundSocks.addWidget(self.__btnDebug)
            self.__btnDebug.clicked.connect(self.__DebugTest)
            self.settingOutboundSocksPanelFromJSONFile(self.outboundSocksJSONFile, True)
        
        self.createOutboundSocksPanelSignals()

        return groupBoxOutboundSocksPanel
    
    def createOutboundSocksPanelSignals(self):
        self.btnOutboundSocksAdd.clicked.connect(self.onbtnOutboundSocksAdd)
        self.btnOutboundSocksChange.clicked.connect(self.onbtnOutboundSocksChange)
        self.btnOutboundSocksClear.clicked.connect(self.onbtnOutboundSocksClear)
        self.btnOutboundSocksDelete.clicked.connect(self.onbtnOutboundSocksDelete)
        self.treeViewoutSocksAddress.clicked.connect(self.ontreeViewoutSocksAddressClicked)

    def onbtnOutboundSocksAdd(self):
        if (self.treeViewoutSocksAddressMode.rowCount() == 0):
            if (self.lineEditOutboundSocksAddress.text() == ""): return
            self.treeViewoutSocksAddressMode.appendRow((QStandardItem(str(self.lineEditOutboundSocksAddress.text())),
                                                        QStandardItem(str(self.spinBoxOutboundSocksPort.value()))))
            self.treeViewoutSocksAddress.setCurrentIndex(self.treeViewoutSocksAddressMode.index(0, 0))
            self.btnOutboundSocksDelete.setEnabled(True)
            self.lineEditOutboundSocksUserName.setEnabled(True)
            self.lineEditOutboundSocksPassword.setEnabled(True)
            self.spinBoxOutboundSocksuerLevel.setEnabled(True)
            self.onbtnOutboundSocksClear()
            return
        
        itemSelection = self.treeViewoutSocksAddress.selectionModel()
        rowCurrent = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row  = rowCurrent.row()
        
        rowCountAdrress = self.treeViewoutSocksAddressMode.rowCount()
        addresses = []
        for i in range(rowCountAdrress):
            addresses.append(self.treeViewoutSocksAddressMode.item(i, 0).text()+":"+self.treeViewoutSocksAddressMode.item(i, 1).text())
        address = self.lineEditOutboundSocksAddress.text()+":"+str(self.spinBoxOutboundSocksPort.value())
        if (root == -1):
            if (address not in addresses and self.lineEditOutboundSocksAddress.text() != ""):
                self.treeViewoutSocksAddressMode.appendRow((QStandardItem(str(self.lineEditOutboundSocksAddress.text())),
                                                            QStandardItem(str(self.spinBoxOutboundSocksPort.value()))))
                self.treeViewoutSocksAddress.setCurrentIndex(
                    self.treeViewoutSocksAddressMode.index(self.treeViewoutSocksAddressMode.rowCount()-1, 0))
                self.lineEditOutboundSocksUserName.setEnabled(True)
                self.lineEditOutboundSocksPassword.setEnabled(True)
                self.spinBoxOutboundSocksuerLevel.setEnabled(True)
                self.onbtnOutboundSocksClear()
                
            if ((self.treeViewoutSocksAddressMode.item(row).hasChildren() == False) and
                (self.lineEditOutboundSocksUserName.text() != "" or self.lineEditOutboundSocksPassword.text() != "")):
                self.treeViewoutSocksAddressMode.item(row).appendRow((QStandardItem(str(self.lineEditOutboundSocksUserName.text())),
                                                                      QStandardItem(str(self.lineEditOutboundSocksPassword.text())),
                                                                      QStandardItem(str(self.spinBoxOutboundSocksuerLevel.value()))))
                self.lineEditOutboundSocksUserName.setDisabled(True)
                self.lineEditOutboundSocksPassword.setDisabled(True)
                self.spinBoxOutboundSocksuerLevel.setDisabled(True)
                self.onbtnOutboundSocksClear()
        else:
            if (self.lineEditOutboundSocksUserName.text() == "" or self.lineEditOutboundSocksPassword.text() == ""):
                return   ### an empty name or password will not be added
            self.treeViewoutSocksAddressMode.item(root).appendRow((QStandardItem(str(self.lineEditOutboundSocksUserName.text())),
                                                                   QStandardItem(str(self.lineEditOutboundSocksPassword.text())),
                                                                   QStandardItem(str(self.spinBoxOutboundSocksuerLevel.value()))))
            ### the newest item always will be selected
            self.treeViewoutSocksAddress.setCurrentIndex(
                self.treeViewoutSocksAddressMode.index(
                    self.treeViewoutSocksAddressMode.item(root).rowCount()-1, 0, rowCurrent.parent()))
            self.onbtnOutboundSocksClear()
            
    def onbtnOutboundSocksChange(self):
        if (self.treeViewoutSocksAddressMode.rowCount() == 0): return
            
        itemSelection = self.treeViewoutSocksAddress.selectionModel()
        rowCurrent = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row  = rowCurrent.row()
        
        rowCountAdrress = self.treeViewoutSocksAddressMode.rowCount()
        addresses = []
        for i in range(rowCountAdrress):
            addresses.append(
                self.treeViewoutSocksAddressMode.item(i, 0).text()+":"+self.treeViewoutSocksAddressMode.item(i, 1).text())
        address = self.lineEditOutboundSocksAddress.text()+":"+str(self.spinBoxOutboundSocksPort.value())
                
        if (root == -1):
            if (address in addresses or self.lineEditOutboundSocksAddress.text() == ""):
                return
            
            users = []  ### change address or port will delete child items, now save child items
            userNumber = self.treeViewoutSocksAddressMode.item(row).rowCount()
            if (self.treeViewoutSocksAddressMode.hasChildren()):
                for i in range(userNumber):
                    users.append((self.treeViewoutSocksAddressMode.item(row).child(i, 0).text(), 
                                  self.treeViewoutSocksAddressMode.item(row).child(i, 1).text()))
            
            self.treeViewoutSocksAddressMode.setItem(row, 0, QStandardItem(self.lineEditOutboundSocksAddress.text()))
            self.treeViewoutSocksAddressMode.setItem(row, 1, QStandardItem(str(self.spinBoxOutboundSocksPort.value())))
            self.treeViewoutSocksAddress.setCurrentIndex(self.treeViewoutSocksAddressMode.index(row, 0))
            
            ###  restore child items
            if (self.treeViewoutSocksAddressMode.hasChildren()):
                for i in range(userNumber):
                    self.treeViewoutSocksAddressMode.item(row).appendRow((QStandardItem(users[i][0]), 
                                                                          QStandardItem(users[i][1]),
                                                                          QStandardItem(users[i][2])))
        
        else:
            if (self.lineEditOutboundSocksUserName.text() == "" or self.lineEditOutboundSocksPassword.text() == ""):
                return
            self.treeViewoutSocksAddressMode.item(root).setChild(row, 0, QStandardItem(self.lineEditOutboundSocksUserName.text()))
            self.treeViewoutSocksAddressMode.item(root).setChild(row, 1, QStandardItem(self.lineEditOutboundSocksPassword.text()))
            self.treeViewoutSocksAddressMode.item(root).setChild(row, 2, QStandardItem(str(self.spinBoxOutboundSocksuerLevel.value())))
            self.treeViewoutSocksAddress.setCurrentIndex(self.treeViewoutSocksAddressMode.index(row, 0, rowCurrent.parent()))
            
    def onbtnOutboundSocksClear(self):
        if (self.lineEditOutboundSocksAddress.isEnabled()):
            self.lineEditOutboundSocksAddress.clear()
            self.spinBoxOutboundSocksPort.setValue(1080)
        if (self.lineEditOutboundSocksUserName.isEnabled()):
            self.lineEditOutboundSocksPassword.clear()
            self.lineEditOutboundSocksUserName.clear()
            self.spinBoxOutboundSocksuerLevel.setValue(0)
            
    def onbtnOutboundSocksDelete(self):
        if (self.treeViewoutSocksAddressMode.rowCount() == 0): return
        
        itemSelection = self.treeViewoutSocksAddress.selectionModel()
        rowCurrent = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row  = rowCurrent.row()

        if (root == -1):
            self.treeViewoutSocksAddressMode.removeRow(row)
            if (self.treeViewoutSocksAddressMode.rowCount() == 0):
                self.lineEditOutboundSocksAddress.setEnabled(True)
                self.spinBoxOutboundSocksPort.setEnabled(True)
                self.lineEditOutboundSocksUserName.setDisabled(True)
                self.lineEditOutboundSocksPassword.setDisabled(True)
            self.onbtnOutboundSocksClear()
        else:
            self.treeViewoutSocksAddressMode.item(root).removeRow(row)
            self.onbtnOutboundSocksClear()
    
    def ontreeViewoutSocksAddressClicked(self):
        itemSelection = self.treeViewoutSocksAddress.selectionModel()
        rowCurrent    = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row  = rowCurrent.row()
        if (root == -1):
            address  = self.treeViewoutSocksAddressMode.item(row, 0).text() 
            port     = self.treeViewoutSocksAddressMode.item(row, 1).text()
            self.lineEditOutboundSocksAddress.setText(address)
            self.spinBoxOutboundSocksPort.setValue(int(port))
            self.lineEditOutboundSocksPassword.clear()
            self.lineEditOutboundSocksUserName.clear()
            self.lineEditOutboundSocksAddress.setEnabled(True)
            self.spinBoxOutboundSocksPort.setEnabled(True)
            if (self.treeViewoutSocksAddressMode.item(row).hasChildren()):
                self.lineEditOutboundSocksUserName.setEnabled(False)
                self.lineEditOutboundSocksPassword.setEnabled(False)
                self.spinBoxOutboundSocksuerLevel.setEnabled(False)
            else:
                self.lineEditOutboundSocksUserName.setEnabled(True)
                self.lineEditOutboundSocksPassword.setEnabled(True)
                self.spinBoxOutboundSocksuerLevel.setEnabled(True)
        else:
            address  = self.treeViewoutSocksAddressMode.item(root, 0).text()
            port     = self.treeViewoutSocksAddressMode.item(root, 1).text()
            user     = self.treeViewoutSocksAddressMode.item(root).child(row, 0).text()
            password = self.treeViewoutSocksAddressMode.item(root).child(row, 1).text()
            level    = self.treeViewoutSocksAddressMode.item(root).child(row, 2).text()
            self.lineEditOutboundSocksUserName.setText(user)
            self.lineEditOutboundSocksPassword.setText(password)
            self.lineEditOutboundSocksAddress.setText(address)
            self.spinBoxOutboundSocksPort.setValue(int(port))
            self.spinBoxOutboundSocksuerLevel.setValue(int(level))
            self.lineEditOutboundSocksAddress.setEnabled(False)
            self.spinBoxOutboundSocksPort.setEnabled(False)
            self.lineEditOutboundSocksUserName.setEnabled(True)
            self.lineEditOutboundSocksPassword.setEnabled(True)
            self.spinBoxOutboundSocksuerLevel.setEnabled(True)
            
    def settingOutboundSocksPanelFromJSONFile(self, outboundSocksJSONFile = {}, openFromJSONFile = True):
        logbook.setisOpenJSONFile(openFromJSONFile)
        self.treeViewoutSocksAddressMode.setRowCount(0)
        
        if (outboundSocksJSONFile == None): outboundSocksJSONFile = {}

        try:
            outboundSocksJSONFile["servers"]
        except KeyError as e:
            logbook.writeLog("OutboundSocks", "KeyError", e)
            outboundSocksJSONFile["servers"] = []
        
        servers = outboundSocksJSONFile["servers"]
        serversNumber = len(servers)
        
        ### just show the first server detail in TabelWidget
        if (serversNumber > 0):
            try:
                self.lineEditOutboundSocksAddress.setText(servers[0]["address"])
            except KeyError as e:
                logbook.writeLog("OutboundSocks", "KeyError", e)
                
            try:
                self.spinBoxOutboundSocksPort.setValue(int(servers[0]["port"]))
            except KeyError as e:
                logbook.writeLog("OutboundSocks", "KeyError", e)
            except (ValueError, TypeError) as e:
                logbook.writeLog("OutboundSocks", "ValueError or TypeError", e)

            for i in range(serversNumber):
                try:
                    usersNumber   = len(servers[i]["users"])
                except KeyError as e:
                    logbook.writeLog("OutboundSocks", "KeyError", e)
                    usersNumber = 0
                try:
                    users         = servers[i]["users"]
                except KeyError as e:
                    logbook.writeLog("OutboundSocks", "KeyError", e)
                try:
                    serverAddress = QStandardItem(str(servers[i]["address"]))
                except KeyError as e:
                    logbook.writeLog("OutboundSocks", "KeyError", e)
                    
                try:
                    serverPort    = QStandardItem(str(servers[i]["port"]))
                except KeyError as e:
                    logbook.writeLog("OutboundSocks", "KeyError", e)
                    
                for j in range(usersNumber):
                    try:
                        user      = QStandardItem(str(users[j]["user"]))
                        password  = QStandardItem(str(users[j]["pass"]))
                        try:
                            level     = QStandardItem(str(users[j]["level"]))
                        except Exception:
                            level     = QStandardItem("0")
                        
                        try:    
                            self.treasureChest.addLevel(users[j]["level"])
                        except Exception:
                            pass
                        serverAddress.appendRow((user, password, level))
                    except KeyError as e:
                        logbook.writeLog("OutboundSocks set user", "KeyError", e)
                    except TypeError as e:
                        logbook.writeLog("OutboundSocks set user", "TypeError", e)
                    except ValueError as e:
                        logbook.writeLog("OutboundSocks set user", "ValueError", e)
                    except:
                        logbook.writeLog("OutboundSocks set user", "unkonw")
                self.treeViewoutSocksAddressMode.appendRow((serverAddress, serverPort))
                    
        ### make a sure add items success
        if (self.treeViewoutSocksAddressMode.rowCount() > 0):
            ### if there no any selectItem, "Add, Modify, Delete" button's slot will crash
            self.treeViewoutSocksAddress.setCurrentIndex(self.treeViewoutSocksAddressMode.index(0, 0))
        
    def createOutboundSocksJSONFile(self):
        outboundSocksJSONFile = {}
        outboundSocksJSONFile["servers"] =  []
        serversNumber = self.treeViewoutSocksAddressMode.rowCount()
        if (serversNumber < 0): return self.outboundSocksJSONFile
        
        for i in range(serversNumber):
            server = {}
            user = {}
            server["address"] = self.treeViewoutSocksAddressMode.item(i, 0).text()
            server["port"]    = int(self.treeViewoutSocksAddressMode.item(i, 1).text())
            server["users"] = []
            if (self.treeViewoutSocksAddressMode.hasChildren()):
                usersNumber = self.treeViewoutSocksAddressMode.item(i).rowCount()
                for j in range(usersNumber):
                    user["user"]  = self.treeViewoutSocksAddressMode.item(i).child(j, 0).text()
                    user["pass"]  = self.treeViewoutSocksAddressMode.item(i).child(j, 1).text()
                    user["level"] = int(self.treeViewoutSocksAddressMode.item(i).child(j, 2).text())
                    try:
                        self.treasureChest.addLevel(user["level"])
                    except Exception:
                        pass
                    server["users"].append(copy.deepcopy(user))
            else:
                server["users"] = []
            outboundSocksJSONFile["servers"].append(copy.deepcopy(server))

        return outboundSocksJSONFile
    
    def clearoutboundSocksPanel(self):
        self.treeViewoutSocksAddressMode.setRowCount(0)
        self.lineEditOutboundSocksAddress.clear()
        self.lineEditOutboundSocksPassword.clear()
        self.lineEditOutboundSocksUserName.clear()
        self.spinBoxOutboundSocksPort.setValue(1080)
        self.spinBoxOutboundSocksuerLevel.setValue(0)
        
    def __DebugTest(self):
        import json
        print(json.dumps(self.createOutboundSocksJSONFile(), indent = 4, sort_keys = False))
Ejemplo n.º 4
0
class OutboundVmessSettingPanel(QWidget):
    def __init__(self):
        super().__init__()
        self.outboundVmessJSONFile = {
            "vnext": [{
                "address":
                "127.0.0.1",
                "port":
                443,
                "users": [{
                    "id": "27848739-7e62-4138-9fd3-098a63964b6b",
                    "alterId": 10,
                    "security": "aes-128-cfb",
                    "level": 0
                }]
            }]
        }
        self.translate = QCoreApplication.translate
        self.labeloutVmess = (self.translate("OutboundVmessSettingPanel",
                                             "Address/AlterID"),
                              self.translate("OutboundVmessSettingPanel",
                                             "Port/Method"),
                              self.translate("OutboundVmessSettingPanel",
                                             "UUID"),
                              self.translate("OutboundVmessSettingPanel",
                                             "Level"))

        self.listMethodoutVmess = "auto", "aes-128-cfb", "aes-128-gcm", "chacha20-poly1305", "none"

    def createOutboundVmessPanel(self):
        self.treeViewOutboundVmessAddress = treeViewOutboundVmessAddress = QTreeView(
        )
        treeViewOutboundVmessAddress.setSelectionMode(
            QAbstractItemView.SingleSelection)
        treeViewOutboundVmessAddress.setSelectionBehavior(
            QAbstractItemView.SelectRows)
        treeViewOutboundVmessAddress.setUniformRowHeights(True)

        self.treeViewOutboundVmessAddressMode = QStandardItemModel()
        self.treeViewOutboundVmessAddressMode.setHorizontalHeaderLabels(
            self.labeloutVmess)
        treeViewOutboundVmessAddress.setModel(
            self.treeViewOutboundVmessAddressMode)

        treeViewOutboundVmessAddress.setItemDelegateForColumn(
            1, toolbox.ComboBoxSpinBoxDelegate(self.listMethodoutVmess))

        self.btnoutVmessNewUser = QPushButton(
            self.translate("OutboundVmessSettingPanel", "New User"))
        self.btnoutVmessNewServer = QPushButton(
            self.translate("OutboundVmessSettingPanel", "New Sever"))
        self.btnoutVmessDelete = QPushButton(
            self.translate("OutboundVmessSettingPanel", "Delete"))

        vboxBtn = QVBoxLayout()
        vboxBtn.addWidget(QLabel())
        vboxBtn.addWidget(QLabel())
        vboxBtn.addWidget(QLabel())
        vboxBtn.addWidget(QLabel())
        vboxBtn.addWidget(self.btnoutVmessNewUser)
        vboxBtn.addWidget(self.btnoutVmessNewServer)
        vboxBtn.addWidget(self.btnoutVmessDelete)

        hboxTreeView = QHBoxLayout()
        hboxTreeView.addWidget(treeViewOutboundVmessAddress)
        hboxTreeView.addLayout(vboxBtn)

        vboxOutBoundVmessUser = QVBoxLayout()
        vboxOutBoundVmessUser.addLayout(hboxTreeView)

        groupBoxOutboundVmessUser = QGroupBox("", self)
        groupBoxOutboundVmessUser.setLayout(vboxOutBoundVmessUser)

        self.createOutboundVmessPanelSignals()

        if (v2rayshellDebug):
            self.__btnDebug = QPushButton("__DebugTest", self)
            self.__btnDebug.clicked.connect(self.__DebugTest)
            vboxOutBoundVmessUser.addWidget(self.__btnDebug)
            self.setLayout(vboxOutBoundVmessUser)
            self.settingOutboundVmessPanelFromJSONFile(
                self.outboundVmessJSONFile, True)
            return

        return groupBoxOutboundVmessUser

    def createOutboundVmessPanelSignals(self):
        self.btnoutVmessDelete.clicked.connect(self.onbtnoutVmessDelete)
        self.btnoutVmessNewServer.clicked.connect(self.onbtnoutVmessNewServer)
        self.btnoutVmessNewUser.clicked.connect(self.onbtnoutVmessNewUser)

    def onbtnoutVmessDelete(self):
        if (not self.treeViewOutboundVmessAddressMode.rowCount()): return

        itemSelection = self.treeViewOutboundVmessAddress.selectionModel()
        rowCurrent = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row = rowCurrent.row()

        if (root == -1):
            self.treeViewOutboundVmessAddressMode.removeRow(row)
        else:
            self.treeViewOutboundVmessAddressMode.item(root).removeRow(row)

    def onbtnoutVmessNewUser(self):
        rowCount = self.treeViewOutboundVmessAddressMode.rowCount()
        if not rowCount:
            self.newRowOutVmess(rowCount)
            self.treeViewOutboundVmessAddress.setCurrentIndex(
                self.treeViewOutboundVmessAddressMode.index(rowCount, 0))
            return

        itemSelection = self.treeViewOutboundVmessAddress.selectionModel()
        rowCurrent = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row = rowCurrent.row()
        if root == -1:
            self.treeViewOutboundVmessAddressMode.item(row).appendRow(
                (QStandardItem("10"), QStandardItem("aes-128-cfb"),
                 QStandardItem(self.createUUID()), QStandardItem("0")))
            self.treeViewOutboundVmessAddress.expand(
                self.treeViewOutboundVmessAddressMode.index(row, 0))
        else:
            self.treeViewOutboundVmessAddressMode.item(root).appendRow(
                (QStandardItem("10"), QStandardItem("aes-128-cfb"),
                 QStandardItem(self.createUUID()), QStandardItem("0")))

    def onbtnoutVmessNewServer(self):
        row = self.treeViewOutboundVmessAddressMode.rowCount()
        if not row:
            self.newRowOutVmess(row)
            self.treeViewOutboundVmessAddress.setCurrentIndex(
                self.treeViewOutboundVmessAddressMode.index(row, 0))
        else:
            r = self.treeViewOutboundVmessAddressMode.item(row - 1)
            if r.hasChildren():
                self.newRowOutVmess(row)

    def newRowOutVmess(self, row):
        self.treeViewOutboundVmessAddressMode.setRowCount(row + 1)
        address = self.treeViewOutboundVmessAddressMode.index(row, 0)
        port = self.treeViewOutboundVmessAddressMode.index(row, 1)
        self.treeViewOutboundVmessAddressMode.setData(address, "127.0.0.1")
        self.treeViewOutboundVmessAddressMode.setData(port, "443")

    def settingOutboundVmessPanelFromJSONFile(self,
                                              outboundVmessJSONFile=None,
                                              openFromJSONFile=False):
        logbook.setisOpenJSONFile(openFromJSONFile)
        self.treeViewOutboundVmessAddressMode.setRowCount(0)

        if (not outboundVmessJSONFile):
            outboundVmessJSONFile = {}

        try:
            outboundVmessJSONFile["vnext"]
        except KeyError as e:
            logbook.writeLog("OutboundVmess", "KeyError", e)
            outboundVmessJSONFile["vnext"] = []

        addressNumber = len(outboundVmessJSONFile["vnext"])

        if (addressNumber):
            addresses = outboundVmessJSONFile["vnext"]

            for i in range(addressNumber):
                try:
                    users = addresses[i]["users"]
                    usersNumber = len(users)
                    serverAddress = QStandardItem(addresses[i]["address"])
                    serverPort = QStandardItem(str(addresses[i]["port"]))
                    if (usersNumber):
                        for j in range(usersNumber):
                            try:
                                uuidString = QStandardItem(str(users[j]["id"]))
                            except Exception:
                                uuidString = QStandardItem("")
                            try:
                                alterId = QStandardItem(
                                    str(users[j]["alterId"]))
                            except Exception:
                                alterId = QStandardItem("")
                            try:
                                security = QStandardItem(
                                    str(users[j]["security"]))
                            except Exception:
                                security = QStandardItem("")
                            try:
                                level = QStandardItem(str(users[j]["level"]))
                            except Exception:
                                level = QStandardItem("0")
                            try:
                                self.treasureChest.addLevel(users[j]["level"])
                            except Exception:
                                pass
                            serverAddress.appendRow(
                                (alterId, security, uuidString, level))
                    self.treeViewOutboundVmessAddressMode.appendRow(
                        (serverAddress, serverPort))
                except KeyError as e:
                    logbook.writeLog("OutboundVmess", "KeyError", e)
                except:
                    logbook.writeLog("OutboundVmess", "unkonw")

        if (self.treeViewOutboundVmessAddressMode.rowCount() > 0):
            self.treeViewOutboundVmessAddress.setCurrentIndex(
                self.treeViewOutboundVmessAddressMode.index(0, 0))

    def createOutboundVmessJSONFile(self):
        outboundVmessJSONFile = {}
        outboundVmessJSONFile["vnext"] = []
        serversNumber = self.treeViewOutboundVmessAddressMode.rowCount()
        if (not serversNumber): return

        for i in range(serversNumber):
            server = {}
            user = {}
            server["address"] = self.treeViewOutboundVmessAddressMode.item(
                i, 0).text()
            server["port"] = int(
                self.treeViewOutboundVmessAddressMode.item(i, 1).text())
            server["users"] = []
            if (self.treeViewOutboundVmessAddressMode.hasChildren()):
                usersNumber = self.treeViewOutboundVmessAddressMode.item(
                    i).rowCount()
                for j in range(usersNumber):
                    user["id"] = self.treeViewOutboundVmessAddressMode.item(
                        i).child(j, 2).text()
                    user["alterId"] = int(
                        self.treeViewOutboundVmessAddressMode.item(i).child(
                            j, 0).text())
                    user[
                        "security"] = self.treeViewOutboundVmessAddressMode.item(
                            i).child(j, 1).text()
                    user["level"] = int(
                        self.treeViewOutboundVmessAddressMode.item(i).child(
                            j, 3).text())
                    try:
                        self.treasureChest.addLevel(user["level"])
                    except Exception:
                        pass
                    server["users"].append(copy.deepcopy(user))
            else:
                server["users"] = []
            outboundVmessJSONFile["vnext"].append(copy.deepcopy(server))

        return outboundVmessJSONFile

    def createUUID(self):
        return str(uuid.uuid4())

    def validateUUID4(self, uuidString):
        try:
            uuid.UUID(uuidString, version=4)
        except ValueError:
            return False
        return True

    def clearOutVmessPanel(self):
        self.treeViewOutboundVmessAddressMode.setRowCount(0)

    def __DebugTest(self):
        import json
        print(
            json.dumps(self.createOutboundVmessJSONFile(),
                       indent=4,
                       sort_keys=False))
Ejemplo n.º 5
0
class OutboundVmessSettingPanel(QWidget):

    def __init__(self):
        super().__init__()
        self.outboundVmessJSONFile = {
                                        "vnext": [
                                            {
                                                "address": "127.0.0.1",
                                                "port": 443,
                                                "users": [
                                                    {
                                                        "id": "27848739-7e62-4138-9fd3-098a63964b6b",
                                                        "alterId": 10,
                                                        "security": "aes-128-cfb",
                                                        "level": 0
                                                    }
                                                ]
                                             }
                                        ]
                                      }
        self.translate = QCoreApplication.translate
        self.labeloutVmess = (self.translate("OutboundVmessSettingPanel", "Address/AlterID"),
                              self.translate("OutboundVmessSettingPanel", "Port/Method"),
                              self.translate("OutboundVmessSettingPanel", "UUID"),
                              self.translate("OutboundVmessSettingPanel", "Level"))
        
        self.listMethodoutVmess = "auto", "aes-128-cfb", "aes-128-gcm", "chacha20-poly1305", "none"

    def createOutboundVmessPanel(self):
        labelAddress = QLabel(
            self.translate("OutboundVmessSettingPanel", "Server Address: "), self)
        self.lineEditOutboundVmessAddress = QLineEdit()
        labelPort = QLabel(
            self.translate("OutboundVmessSettingPanel", "Port: "), self)
        self.spinBoxOutboundVmessPort = QSpinBox()
        self.spinBoxOutboundVmessPort.setRange(0, 65535)
        self.spinBoxOutboundVmessPort.setValue(443)
        
        labelUIID = QLabel(
            self.translate("OutboundVmessSettingPanel", "UUID: "), self)
        self.lineEditOutboundVmessUUID = QLineEdit()
        self.btnoutVmessGerateUUID = QPushButton(
            self.translate("OutboundVmessSettingPanel", "Gerate UUID"), self)
        labelAlterID = QLabel(
            self.translate("OutboundVmessSettingPanel", "AlterID: "), self)
        self.spinBoxOutboundVmessAlterID = QSpinBox()
        self.comboBoxOutboundVmessMethod = QComboBox()
        self.spinBoxOutboundVmessAlterID.setRange(0, 65535)
        self.lineEditOutboundVmessUUID.setInputMask("HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH;_")
        self.comboBoxOutboundVmessMethod.addItems(self.listMethodoutVmess)
        
        labelLevel = QLabel(
            self.translate("OutboundVmessSettingPanel", "User Level: "))
        self.spinBoxOutboundVmessuserLevel = QSpinBox()
        self.spinBoxOutboundVmessuserLevel.setRange(0, 65535)
        self.spinBoxOutboundVmessuserLevel.setValue(0)
        
        hboxuserLevel = QHBoxLayout()
        hboxuserLevel.addWidget(labelLevel)
        hboxuserLevel.addWidget(self.spinBoxOutboundVmessuserLevel)
        
        hboxAddress = QHBoxLayout()
        hboxAddress.addWidget(labelAddress)
        hboxAddress.addWidget(self.lineEditOutboundVmessAddress)
        hboxAddress.addWidget(labelPort)
        hboxAddress.addWidget(self.spinBoxOutboundVmessPort)
        hboxAddress.addStretch()
        
        self.groupBoxOutBoundVmessAddress = QGroupBox("", self)
        self.groupBoxOutBoundVmessAddress.setLayout(hboxAddress)
        
        hboxID = QHBoxLayout()
        hboxID.addWidget(labelUIID)
        hboxID.addWidget(self.lineEditOutboundVmessUUID)
        hboxID.addWidget(self.btnoutVmessGerateUUID)
        
        hboxAlterID = QHBoxLayout()
        hboxAlterID.addLayout(hboxuserLevel)
        hboxAlterID.addWidget(labelAlterID)
        hboxAlterID.addWidget(self.spinBoxOutboundVmessAlterID)
        hboxAlterID.addWidget(self.comboBoxOutboundVmessMethod)
        hboxAlterID.addStretch()
        
        self.treeViewOutboundVmessAddress = treeViewOutboundVmessAddress = QTreeView()
        treeViewOutboundVmessAddress.setSelectionMode(QAbstractItemView.SingleSelection)
        treeViewOutboundVmessAddress.setSelectionBehavior(QAbstractItemView.SelectRows)
        treeViewOutboundVmessAddress.setUniformRowHeights(True)
        treeViewOutboundVmessAddress.setEditTriggers(QAbstractItemView.NoEditTriggers)
        
        self.treeViewOutboundVmessAddressMode = QStandardItemModel()
        self.treeViewOutboundVmessAddressMode.setHorizontalHeaderLabels(self.labeloutVmess)
        treeViewOutboundVmessAddress.setModel(self.treeViewOutboundVmessAddressMode)
        
        self.btnoutVmessClear = QPushButton(
            self.translate("OutboundVmessSettingPanel", "Clear"))
        self.btnoutVmessChange = QPushButton(
            self.translate("OutboundVmessSettingPanel", "Modify"))
        self.btnoutVmessAdd = QPushButton(
            self.translate("OutboundVmessSettingPanel", "Add"))
        self.btnoutVmessDelete = QPushButton(
            self.translate("OutboundVmessSettingPanel", "Delete"))

        vboxBtn = QVBoxLayout()
        vboxBtn.addStretch()
        vboxBtn.addWidget(self.btnoutVmessAdd)
        vboxBtn.addWidget(self.btnoutVmessClear)
        vboxBtn.addWidget(self.btnoutVmessChange)
        vboxBtn.addWidget(self.btnoutVmessDelete)

        vboxID = QVBoxLayout()
        vboxID.addLayout(hboxID)
        vboxID.addLayout(hboxAlterID)
        
        self.groupBoxOutBoundVmessID = QGroupBox("", self)
        self.groupBoxOutBoundVmessID.setLayout(vboxID)
        self.groupBoxOutBoundVmessID.setEnabled(False)
        
        hboxTreeView = QHBoxLayout()
        hboxTreeView.addWidget(treeViewOutboundVmessAddress)
        hboxTreeView.addLayout(vboxBtn)
        
        vboxOutBoundVmessUser = QVBoxLayout()
        vboxOutBoundVmessUser.addWidget(self.groupBoxOutBoundVmessAddress)
        vboxOutBoundVmessUser.addWidget(self.groupBoxOutBoundVmessID)
        vboxOutBoundVmessUser.addLayout(hboxTreeView)
        
        self.groupBoxOutboundVmessUser = QGroupBox("", self)
        self.groupBoxOutboundVmessUser.setLayout(vboxOutBoundVmessUser)
        
        self.createOutboundVmessPanelSignals()

        if(v2rayshellDebug):
            self.__btnDebug = QPushButton("__DebugTest", self)
            self.__btnDebug.clicked.connect(self.__DebugTest)
            vboxOutBoundVmessUser.addWidget(self.__btnDebug)
            self.setLayout(vboxOutBoundVmessUser)
            self.settingOutboundVmessPanelFromJSONFile(self.outboundVmessJSONFile, True)
            return
            
        return self.groupBoxOutboundVmessUser
    
    def createOutboundVmessPanelSignals(self):
        self.btnoutVmessGerateUUID.clicked.connect(self.onbtnoutVmessGerateUUID)
        self.treeViewOutboundVmessAddress.clicked.connect(self.ontreeViewOutboundVmessAddress)
        self.btnoutVmessClear.clicked.connect(self.onbtnoutVmessClear)
        self.btnoutVmessAdd.clicked.connect(self.onbtnoutVmessAdd)
        self.btnoutVmessDelete.clicked.connect(self.onbtnoutVmessDelete)
        self.btnoutVmessChange.clicked.connect(self.onbtnoutVmessChange)
        
    def onbtnoutVmessGerateUUID(self):
        self.lineEditOutboundVmessUUID.setText(self.createUUID())
        
    def onbtnoutVmessClear(self):
        if (self.groupBoxOutBoundVmessAddress.isEnabled()):
            self.outVmessClearAddress()
        if (self.groupBoxOutBoundVmessID.isEnabled()):
            self.outVmessClearID()
            
    def outVmessClearID(self):
        self.lineEditOutboundVmessUUID.clear()
        self.spinBoxOutboundVmessAlterID.setValue(10)
        self.comboBoxOutboundVmessMethod.setCurrentText("aes-128-cfb")
        self.spinBoxOutboundVmessuserLevel.setValue(0)
        
    def outVmessClearAddress(self):
        self.lineEditOutboundVmessAddress.clear()
        self.spinBoxOutboundVmessPort.setValue(443)
    
    def ontreeViewOutboundVmessAddress(self):
        itemSelection = self.treeViewOutboundVmessAddress.selectionModel()
        rowCurrent = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row = rowCurrent.row()
        
        if (root == -1):
            self.groupBoxOutBoundVmessAddress.setEnabled(True)
            address = self.treeViewOutboundVmessAddressMode.item(row, 0).text() 
            port = self.treeViewOutboundVmessAddressMode.item(row, 1).text()
            self.lineEditOutboundVmessAddress.setText(address)
            self.spinBoxOutboundVmessPort.setValue(int(port))
            self.outVmessClearID()
            if (self.treeViewOutboundVmessAddressMode.item(row).hasChildren()):
                self.groupBoxOutBoundVmessID.setEnabled(False)
            else:
                self.groupBoxOutBoundVmessID.setEnabled(True)
        else:
            self.groupBoxOutBoundVmessID.setEnabled(True)
            self.groupBoxOutBoundVmessAddress.setEnabled(False)
            
            address = self.treeViewOutboundVmessAddressMode.item(root, 0).text()
            port = self.treeViewOutboundVmessAddressMode.item(root, 1).text()
            uuidString = self.treeViewOutboundVmessAddressMode.item(root).child(row, 2).text()
            alterId = self.treeViewOutboundVmessAddressMode.item(root).child(row, 0).text()
            security = self.treeViewOutboundVmessAddressMode.item(root).child(row, 1).text()
            level = self.treeViewOutboundVmessAddressMode.item(root).child(row, 3).text()
            self.lineEditOutboundVmessAddress.setText(address)
            self.spinBoxOutboundVmessPort.setValue(int(port))
            self.lineEditOutboundVmessUUID.setText(uuidString)
            self.spinBoxOutboundVmessAlterID.setValue(int(alterId))
            self.comboBoxOutboundVmessMethod.setCurrentText(security)
            self.spinBoxOutboundVmessuserLevel.setValue(int(level))

    def onbtnoutVmessChange(self):
        if (not self.treeViewOutboundVmessAddressMode.rowCount()): return
        
        itemSelection = self.treeViewOutboundVmessAddress.selectionModel()
        rowCurrent = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row = rowCurrent.row()
        
        rowCountAddress = self.treeViewOutboundVmessAddressMode.rowCount()
        addresses = []
        for i in range(rowCountAddress):
            # make sure no Duplicate address
            addresses.append(
                self.treeViewOutboundVmessAddressMode.item(i, 0).text() + ":" + self.treeViewOutboundVmessAddressMode.item(i, 1).text())
        address = self.lineEditOutboundVmessAddress.text() + ":" + str(self.spinBoxOutboundVmessPort.value())

        if (root == -1):
            if ((address in addresses) or (self.lineEditOutboundVmessAddress.text() == "")):
                return
            
            users = []
            usersNumber = self.treeViewOutboundVmessAddressMode.item(row).rowCount()
            if (self.treeViewOutboundVmessAddressMode.hasChildren()):  # or use usersNumber > 0  but hasChildren() more clearer
                for i in range(usersNumber):
                    alterID = self.treeViewOutboundVmessAddressMode.item(row).child(i, 0).text()
                    security = self.treeViewOutboundVmessAddressMode.item(row).child(i, 1).text()
                    uuidString = self.treeViewOutboundVmessAddressMode.item(row).child(i, 2).text()
                    level = self.treeViewOutboundVmessAddressMode.item(row).child(i, 3).text()
                    users.append((alterID, security, uuidString, level))
            
            self.treeViewOutboundVmessAddressMode.setItem(
                row, 0, QStandardItem(str(self.lineEditOutboundVmessAddress.text())))
            self.treeViewOutboundVmessAddressMode.setItem(
                row, 1, QStandardItem(str(self.spinBoxOutboundVmessPort.value())))
            self.treeViewOutboundVmessAddress.setCurrentIndex(
                self.treeViewOutboundVmessAddressMode.index(row, 0))
            
            if (self.treeViewOutboundVmessAddressMode.hasChildren()):
                for i in range(usersNumber):
                    alterID = QStandardItem(str(users[i][0])) 
                    security = QStandardItem(str(users[i][1]))
                    uuidString = QStandardItem(str(users[i][2]))
                    level = QStandardItem(str(users[i][3]))
                    self.treeViewOutboundVmessAddressMode.item(row).appendRow((alterID, security, uuidString, level))
        else:
            if (self.lineEditOutboundVmessUUID.text() == "----"): return
            alterID = QStandardItem(str(self.spinBoxOutboundVmessAlterID.value()))
            security = QStandardItem(str(self.comboBoxOutboundVmessMethod.currentText()))
            uuidString = QStandardItem(str(self.lineEditOutboundVmessUUID.text()))
            level = QStandardItem(str(self.spinBoxOutboundVmessuserLevel.value()))
            self.treeViewOutboundVmessAddressMode.item(root).setChild(row, 0, alterID)
            self.treeViewOutboundVmessAddressMode.item(root).setChild(row, 1, security)
            self.treeViewOutboundVmessAddressMode.item(root).setChild(row, 2, uuidString)
            self.treeViewOutboundVmessAddressMode.item(root).setChild(row, 3, level)
            self.treeViewOutboundVmessAddress.setCurrentIndex(
                self.treeViewOutboundVmessAddressMode.index(row, 0, rowCurrent.parent()))

    def onbtnoutVmessAdd(self):
        if (not self.treeViewOutboundVmessAddressMode.rowCount()):
            if (not self.lineEditOutboundVmessAddress.text()): return
            self.treeViewOutboundVmessAddressMode.appendRow((QStandardItem(str(self.lineEditOutboundVmessAddress.text())),
                                                             QStandardItem(str(self.spinBoxOutboundVmessPort.value()))))
            self.treeViewOutboundVmessAddress.setCurrentIndex(
                self.treeViewOutboundVmessAddressMode.index(0, 0))
            self.btnoutVmessDelete.setEnabled(True)
            self.groupBoxOutBoundVmessID.setEnabled(True)
            self.onbtnoutVmessClear()
            return
        
        itemSelection = self.treeViewOutboundVmessAddress.selectionModel()
        rowCurrent = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row = rowCurrent.row()
        
        rowCountAddress = self.treeViewOutboundVmessAddressMode.rowCount()
        addresses = []
        for i in range(rowCountAddress):
            # make sure no Duplicate address
            addresses.append(self.treeViewOutboundVmessAddressMode.item(i, 0).text() + ":" + self.treeViewOutboundVmessAddressMode.item(i, 1).text())
        address = self.lineEditOutboundVmessAddress.text() + ":" + str(self.spinBoxOutboundVmessPort.value())
        
        if (root == -1):  # user clicked address
            if (address not in addresses and self.lineEditOutboundVmessAddress.text() != ""):
                self.treeViewOutboundVmessAddressMode.appendRow((QStandardItem(str(self.lineEditOutboundVmessAddress.text())),
                                                             QStandardItem(str(self.spinBoxOutboundVmessPort.value()))))
                self.treeViewOutboundVmessAddress.setCurrentIndex(
                    self.treeViewOutboundVmessAddressMode.index(
                        self.treeViewOutboundVmessAddressMode.rowCount() - 1, 0))
                self.groupBoxOutBoundVmessID.setEnabled(True)
                self.onbtnoutVmessClear()
                     
            if (not self.treeViewOutboundVmessAddressMode.item(row).hasChildren() and
                (self.lineEditOutboundVmessUUID.text() != "----")):
                alterID = QStandardItem(str(self.spinBoxOutboundVmessAlterID.value()))
                security = QStandardItem(str(self.comboBoxOutboundVmessMethod.currentText()))
                uuidString = QStandardItem(str(self.lineEditOutboundVmessUUID.text()))
                level = QStandardItem(str(self.spinBoxOutboundVmessuserLevel.value()))
                self.treeViewOutboundVmessAddressMode.item(row).appendRow((alterID, security, uuidString, level))                                              
                self.onbtnoutVmessClear()
        else:
            if (self.lineEditOutboundVmessUUID.text() == "----"): return  # an empty UUID not allow
            alterID = QStandardItem(str(self.spinBoxOutboundVmessAlterID.value()))
            security = QStandardItem(str(self.comboBoxOutboundVmessMethod.currentText()))
            uuidString = QStandardItem(str(self.lineEditOutboundVmessUUID.text()))
            level = QStandardItem(str(self.spinBoxOutboundVmessuserLevel.value()))
            self.treeViewOutboundVmessAddressMode.item(root).appendRow((alterID, security, uuidString, level))
            
            # the newest item always will be selected
            self.treeViewOutboundVmessAddress.setCurrentIndex(
                self.treeViewOutboundVmessAddressMode.index(
                    self.treeViewOutboundVmessAddressMode.item(root).rowCount() - 1, 0, rowCurrent.parent()))    
            self.onbtnoutVmessClear()
            
    def onbtnoutVmessDelete(self):
        if (not self.treeViewOutboundVmessAddressMode.rowCount()): return
        
        itemSelection = self.treeViewOutboundVmessAddress.selectionModel()
        rowCurrent = itemSelection.selectedIndexes()[0]
        root = rowCurrent.parent().row()
        row = rowCurrent.row()
        
        if (root == -1):
            self.treeViewOutboundVmessAddressMode.removeRow(row)
            if (not self.treeViewOutboundVmessAddressMode.rowCount()):
                self.onbtnoutVmessClear()
                self.groupBoxOutBoundVmessAddress.setEnabled(True)
                self.groupBoxOutBoundVmessID.setDisabled(True)
            self.onbtnoutVmessClear()
        else:
            self.treeViewOutboundVmessAddressMode.item(root).removeRow(row)
            self.onbtnoutVmessClear()
          
    def settingOutboundVmessPanelFromJSONFile(self, outboundVmessJSONFile=None, openFromJSONFile=False):
        logbook.setisOpenJSONFile(openFromJSONFile)
        self.treeViewOutboundVmessAddressMode.setRowCount(0)
        
        if (not outboundVmessJSONFile): outboundVmessJSONFile = {}

        try:
            outboundVmessJSONFile["vnext"]
        except KeyError as e:
            logbook.writeLog("OutboundVmess", "KeyError", e)
            outboundVmessJSONFile["vnext"] = []
            
        addressNumber = len(outboundVmessJSONFile["vnext"])
        
        if (addressNumber):
            addresses = outboundVmessJSONFile["vnext"]
            try:
                self.lineEditOutboundVmessAddress.setText(str(addresses[0]["address"]))
            except KeyError as e:
                logbook.writeLog("OutboundVmess", "KeyError", e)
            except ValueError as e:
                logbook.writeLog("OutboundVmess", "KeyError", e)
                
            try:
                self.spinBoxOutboundVmessPort.setValue(int(addresses[0]["port"]))
            except KeyError as e:
                logbook.writeLog("OutboundVmess", "KeyError", e)
            except (TypeError, ValueError) as e:
                logbook.writeLog("OutboundVmess", "ValueError or TypeError", e)
            
            for i in range(addressNumber):
                try:
                    users = addresses[i]["users"]
                    usersNumber = len(users)
                    serverAddress = QStandardItem(addresses[i]["address"])
                    serverPort = QStandardItem(str(addresses[i]["port"]))
                    if (usersNumber):
                        for j in range(usersNumber):
                            try:
                                uuidString = QStandardItem(str(users[j]["id"]))
                            except Exception: uuidString = QStandardItem("")
                            try:
                                alterId = QStandardItem(str(users[j]["alterId"]))
                            except Exception: alterId = QStandardItem("")
                            try:
                                security = QStandardItem(str(users[j]["security"]))
                            except Exception: security = QStandardItem("")
                            try:
                                level = QStandardItem(str(users[j]["level"]))
                            except Exception: level = QStandardItem("0")
                            try:
                                self.treasureChest.addLevel(users[j]["level"])
                            except Exception:pass
                            serverAddress.appendRow((alterId, security, uuidString, level))                        
                    self.treeViewOutboundVmessAddressMode.appendRow((serverAddress, serverPort))
                except KeyError as e:
                    logbook.writeLog("OutboundVmess", "KeyError", e)
                except:
                    logbook.writeLog("OutboundVmess", "unkonw")
        
        if (self.treeViewOutboundVmessAddressMode.rowCount() > 0):
            self.treeViewOutboundVmessAddress.setCurrentIndex(self.treeViewOutboundVmessAddressMode.index(0, 0))

    def createOutboundVmessJSONFile(self):
        outboundVmessJSONFile = {}
        outboundVmessJSONFile["vnext"] = []
        serversNumber = self.treeViewOutboundVmessAddressMode.rowCount()
        if (not serversNumber): return self.outboundVmessJSONFile
        
        for i in range(serversNumber):
            server = {}
            user = {}
            server["address"] = self.treeViewOutboundVmessAddressMode.item(i, 0).text()
            server["port"] = int(self.treeViewOutboundVmessAddressMode.item(i, 1).text())
            server["users"] = []
            if (self.treeViewOutboundVmessAddressMode.hasChildren()):
                usersNumber = self.treeViewOutboundVmessAddressMode.item(i).rowCount()
                for j in range(usersNumber):
                    user["id"] = self.treeViewOutboundVmessAddressMode.item(i).child(j, 2).text()
                    user["alterId"] = int(self.treeViewOutboundVmessAddressMode.item(i).child(j, 0).text())
                    user["security"] = self.treeViewOutboundVmessAddressMode.item(i).child(j, 1).text()
                    user["level"] = int(self.treeViewOutboundVmessAddressMode.item(i).child(j, 3).text())
                    try:
                        self.treasureChest.addLevel(user["level"])
                    except Exception:
                        pass
                    server["users"].append(copy.deepcopy(user))
            else:
                server["users"] = []
            outboundVmessJSONFile["vnext"].append(copy.deepcopy(server))
        
        return outboundVmessJSONFile

    def clearoutboundVmessPanel(self):
        self.treeViewOutboundVmessAddressMode.setRowCount(0)
        self.lineEditOutboundVmessAddress.clear()
        self.lineEditOutboundVmessUUID.clear()
        self.comboBoxOutboundVmessMethod.setCurrentIndex(0)
        self.spinBoxOutboundVmessAlterID.setValue(10)
        self.spinBoxOutboundVmessPort.setValue(443)
        self.spinBoxOutboundVmessuserLevel.setValue(0)
                     
    def createUUID(self):
        return str(uuid.uuid4())
    
    def validateUUID4(self, uuidString):
        try:
            uuid.UUID(uuidString, version=4)
        except ValueError:
            return False
        return True
        
    def __DebugTest(self):
        import json
        print(json.dumps(self.createOutboundVmessJSONFile(), indent=4, sort_keys=False))
Ejemplo n.º 6
0
class MainWindow(QMainWindow):

    try:
        OpenAddonAdder = pyqtSignal()
        OpenSettingsWindow = pyqtSignal()
        OutputUpdater = pyqtSignal(str)
        PromptUpdate = pyqtSignal(list)
        DownloadStart = pyqtSignal()
        MessageBox = pyqtSignal(str, str, str)
        UpdateTreeView = pyqtSignal()
        AddAddon = pyqtSignal(Addon, QTreeView, QStandardItemModel)
        # UpdateProgressBarValue = pyqtSignal(int)
        # UpdateProgressBarMax = pyqtSignal(int)
        RemoveAddon = pyqtSignal(str)
        ForceUpdateAddon = pyqtSignal(Addon)
        LoadingGifSignal = pyqtSignal(bool)
        SetUpdateCount = pyqtSignal(int, int)

    except Exception as e:
        print(e)

    def __init__(self):
        super(QMainWindow, self).__init__()

        self.window = QMainWindow()
        self.window.ui = Ui_MainWindow()
        self.window.ui.setupUi(self)
        self.app = QApplication(sys.argv)

        self.settings = Settings()
        self.movie = QMovie(":/app/loading_icon.gif")

        self.download_worker = Worker(self.execute_download)
        self.update_worker = Worker(self.execute_check_updates)

        self.tree_model = self.window.ui.tviewAddons
        self.model = QStandardItemModel(self.tree_model)

        self.window.ui.actionClose.triggered.connect(self.close)
        self.window.ui.actionAbout.triggered.connect(self.open_about_window)

        self.init_ui()

    def closeEvent(self, event):
        if self.settings.config['settings']['prompt_to_close']:
            prompt = QMessageBox.question(self, 'Confirmation',
                                          'Are you sure you want to quit?',
                                          QMessageBox.Yes, QMessageBox.No)

            if prompt == QMessageBox.Yes:
                event.accept()
            else:
                event.ignore()

    def init_ui(self):
        self.window.ui.splitter.setStyleSheet(HANDLE_STYLE)

        self.OpenAddonAdder.connect(self.add_addon)
        self.OpenSettingsWindow.connect(self.show_settings_window)
        self.OutputUpdater.connect(self.insert_output_text)
        self.PromptUpdate.connect(self.prompt_to_update)
        self.DownloadStart.connect(self.execute_download)
        self.MessageBox.connect(self.show_message_box)
        self.UpdateTreeView.connect(self.update_tree_view)
        self.AddAddon.connect(self.add_addon_to_tree_view)
        # self.UpdateProgressBarValue.connect(self.set_progress_bar_value)
        # self.UpdateProgressBarMax.connect(self.set_progress_bar_max)
        self.RemoveAddon.connect(self.remove_addon)
        self.ForceUpdateAddon.connect(self.force_update_addon)
        self.LoadingGifSignal.connect(self.toggle_loading_gif)
        self.SetUpdateCount.connect(self.set_update_count_value)

        self.window.ui.actionAddAddon.triggered.connect(
            self.OpenAddonAdder.emit)
        self.window.ui.actionSettings.triggered.connect(
            self.OpenSettingsWindow.emit)
        self.window.ui.btnCheckForUpdates.clicked.connect(
            self.update_worker.start)
        self.window.ui.btnDownloadUpdates.clicked.connect(
            self.download_worker.start)
        self.window.ui.actionUpdateTreeView.triggered.connect(
            self.UpdateTreeView.emit)

        # self.UpdateProgressBarMax.emit(10)
        # self.UpdateProgressBarValue.emit(0)
        # self.window.ui.progressBar.setVisible(False)

        # Setting the header to hidden removes the drag bar for column width resizing.
        # self.window.ui.tviewAddons.setHeaderHidden(True)

        self.UpdateTreeView.emit()

        self.settings.check_for_wow_directory(self)
        self.window.ui.label.setHidden(True)
        self.window.ui.btnDownloadUpdates.setHidden(True)

        self.window.ui.tviewAddons.setColumnWidth(0, 300)

        self.window.ui.lblLoadingMovie.setMovie(self.movie)
        self.window.ui.lblLoadingMovie.setMaximumHeight(50)
        self.window.ui.lblLoadingMovie.setScaledContents(True)
        self.window.ui.lblLoadingMovie.setSizePolicy(QSizePolicy.Expanding,
                                                     QSizePolicy.Expanding)
        self.window.ui.frameUpdate.setVisible(False)

    @pyqtSlot()
    def add_addon(self):
        addon_window = AddonWindow(self.settings, self)
        addon_window.exec()

    @pyqtSlot()
    def open_about_window(self):
        about_window = AboutWindow(self)
        about_window.exec()

    @pyqtSlot(str)
    def insert_output_text(self, text):
        self.window.ui.teditOutput.insertPlainText(text + '\n')
        self.window.ui.teditOutput.moveCursor(QTextCursor.End)

    @pyqtSlot()
    def show_settings_window(self):
        settings_window = SettingsWindow(self)
        settings_window.exec()

    @pyqtSlot(int)
    def set_progress_bar_value(self, val):
        self.window.ui.progressBar.setValue(val)

    @pyqtSlot(bool)
    def toggle_loading_gif(self, enabled):
        if enabled:
            self.window.ui.frameUpdate.setVisible(True)
            self.window.ui.btnCheckForUpdates.setVisible(False)
            self.movie.start()
        else:
            self.window.ui.frameUpdate.setVisible(False)
            self.window.ui.btnCheckForUpdates.setVisible(True)
            self.movie.stop()

    @pyqtSlot(int, int)
    def set_update_count_value(self, current, max):
        self.window.ui.lblCurrentUpdate.setText("( {0} out of {1} )".format(
            current, max))

    @pyqtSlot(int)
    def set_progress_bar_max(self, val):
        self.window.ui.progressBar.setMaximum(val)

    @pyqtSlot(Addon, QTreeView, QStandardItemModel)
    def add_addon_to_tree_view(self, addon, tree_model, model):
        tree_model.setModel(model)

        parent_item = QStandardItem(addon.name)
        col1 = QStandardItem()

        url_item = QStandardItem()
        remove_addon_item = QStandardItem()
        update_addon_item = QStandardItem()

        # Create a QLabel to allow following hyperlinks in the table.
        url_label = QLabel()
        url_label.setTextFormat(1)
        url_label.setOpenExternalLinks(True)
        url_text = "<a href=\"" + addon.url + "\"> " + addon.name + "</a>"
        url_label.setText(url_text)

        remove_addon_button = QPushButton()
        remove_addon_button.setText("Remove {0}".format(addon.name))
        remove_addon_button.clicked.connect(
            lambda: self.RemoveAddon.emit(addon.name))
        remove_addon_button.setMaximumSize(
            80 + (len(remove_addon_button.text()) * 5), 30)

        update_addon_button = QPushButton()
        update_addon_button.setText("Force Update {0}".format(addon.name))
        update_addon_button.clicked.connect(
            lambda: self.ForceUpdateAddon.emit(addon))
        update_addon_button.setMaximumSize(
            80 + (len(remove_addon_button.text()) * 5), 30)

        curr_ver_item = QStandardItem(addon.current_version)
        latest_ver_item = QStandardItem(addon.latest_version)
        update_date_item = QStandardItem(addon.last_update_date)

        logging.debug("Parent item: {0}".format(addon.name))

        model.appendRow([parent_item, col1])

        url_item_identifier = QStandardItem("Addon Link: ")
        curr_ver_item_identifier = QStandardItem("Current Version: ")
        latest_ver_item_identifier = QStandardItem("Latest Version: ")
        remove_addon_item_identifier = QStandardItem("Remove Addon: ")
        update_date_item_identifier = QStandardItem("Date Updated: ")
        force_update_identifier = QStandardItem("Update: ")

        # Append URL, Current Version, and Latest Version to the parent
        parent_item.appendRow([url_item_identifier, url_item])

        # Append URL as a QLabel to allow the hyperlink to be clicked on.
        self.window.ui.tviewAddons.setIndexWidget(url_item.index(), url_label)

        parent_item.appendRow([curr_ver_item_identifier, curr_ver_item])
        parent_item.appendRow([latest_ver_item_identifier, latest_ver_item])
        parent_item.appendRow([update_date_item_identifier, update_date_item])

        parent_item.appendRow(
            [remove_addon_item_identifier, remove_addon_item])
        self.window.ui.tviewAddons.setIndexWidget(remove_addon_item.index(),
                                                  remove_addon_button)

        parent_item.appendRow([force_update_identifier, update_addon_item])
        self.window.ui.tviewAddons.setIndexWidget(update_addon_item.index(),
                                                  update_addon_button)

        # self.window.ui.tviewAddons.setColumnWidth(0, self.window.ui.tviewAddons.columnWidth(0) + 50)

        # Comment out header as I don't like the look at the moment.
        self.model.setHeaderData(0, 0x01, "Addons")
        self.model.setHeaderData(1, 0x01, "")

    @pyqtSlot(str)
    def remove_addon(self, addon_name):
        if addon_name not in self.settings.addons['addons']:
            return

        message_box = QMessageBox.question(
            None, "Confirmation",
            "Are you sure you want to remove {0}?".format(addon_name),
            QMessageBox.Yes, QMessageBox.No)
        if message_box == QMessageBox.Yes:
            del self.settings.addons['addons'][addon_name]
            # print(self.settings.data.pop(key, None))
            self.settings.save_addons()
            self.settings.load_addons()

            index = self.window.ui.tviewAddons.selectionModel().selectedRows(
            )[0]
            parent = index.parent()

            self.window.ui.tviewAddons.selectionModel().setCurrentIndex(
                self.window.ui.tviewAddons.indexAbove(index),
                QItemSelectionModel.ClearAndSelect)
            self.model.removeRow(parent.row())

    @pyqtSlot(Addon)
    def force_update_addon(self, addon):
        if addon.name not in self.settings.addons['addons']:
            return

        message_box = QMessageBox.question(
            None, "Confirmation",
            "Are you sure you want to force update {0}?".format(addon.name),
            QMessageBox.Yes, QMessageBox.No)

        if message_box == QMessageBox.Yes:
            addon.addon_source = addon.get_website_type()
            self.settings.files_to_update = [addon]
            # self.DownloadStart.emit()
            self.download_worker.start()

    @pyqtSlot()
    def update_tree_view(self):
        tree_data = self.settings.addons['addons']
        logging.debug("Tree view data: {0}".format(tree_data))

        # No addons are loaded.
        # TODO: Insert blank row indicating there are no addons.
        if len(tree_data) == 0:
            pass
        if self.model.hasChildren():
            self.model.removeRows(0, self.model.rowCount())

        for parent_name in tree_data:
            current_addon = Addon(tree_data[parent_name]['url'],
                                  tree_data[parent_name]['name'],
                                  tree_data[parent_name]['current_version'],
                                  tree_data[parent_name]['latest_version'],
                                  tree_data[parent_name]['last_update_date'])

            self.AddAddon.emit(current_addon, self.tree_model, self.model)

        self.window.ui.tviewAddons.sortByColumn(0, 0x00)

    @pyqtSlot(str, str, str)
    def show_message_box(self, message='', inform='', message_type='warn'):
        message_box = QMessageBox()

        if message_type == 'inform':
            message_box.setIcon(QMessageBox.Information)
        elif message_type == 'warn':
            message_box.setIcon(QMessageBox.Warning)
        else:
            message_box.setIcon(QMessageBox.Critical)

        message_box.setStandardButtons(QMessageBox.Ok)
        message_box.setWindowTitle("Hey Listen!")
        message_box.setText(message)
        message_box.setInformativeText(inform)
        message_box.setWindowIcon(QIcon(":/app/icon.ico"))
        message_box.exec()

    def execute_check_updates(self):

        if not self.settings.check_for_wow_directory(self):
            return

        if len(self.settings.addons['addons']) == 0:
            self.MessageBox.emit(
                "No AddOns have been specified.",
                "To add an addon, press 'Addon' -> 'Add Addon' and enter the URL of the addon.",
                "warn")
            return

        self.window.ui.btnCheckForUpdates.setText(
            "Checking {0} Addons For Updates...".format(
                len(self.settings.addons['addons'])))
        self.window.ui.btnCheckForUpdates.setDisabled(True)
        self.OutputUpdater.emit("Checking for updates...")

        updater = UpdateChecker(self)
        self.LoadingGifSignal.emit(True)

        update_list = updater.check_for_updates()
        self.LoadingGifSignal.emit(False)

        self.window.ui.btnCheckForUpdates.setText("Check For Updates")
        self.window.ui.btnCheckForUpdates.setEnabled(True)

        # if update_list:
        self.PromptUpdate.emit(update_list)

    @pyqtSlot(list)
    def prompt_to_update(self, update_list):

        if update_list:
            self.window.ui.btnDownloadUpdates.setVisible(True)
            self.OutputUpdater.emit("AddOns out of date:")
            for addon in update_list:
                self.OutputUpdater.emit(
                    "\n{0}: \n\tCurrent version: {1} \n\tNew version:      {2}\n"
                    .format(addon.name, addon.current_version,
                            addon.latest_version))
            message_box = QMessageBox.question(
                None, "Updates found",
                "{0} update{1} found. Would you like to download {2} now?".
                format(len(update_list), "s" if len(update_list) > 1 else "",
                       "them" if len(update_list) > 1 else "it"),
                QMessageBox.Yes, QMessageBox.No)
            if message_box == QMessageBox.Yes:
                self.download_worker.start()

        else:
            # message_box = QMessageBox()
            # message_box.setWindowTitle("Checker")
            # message_box.setText("All AddOns are up to date!")
            self.OutputUpdater.emit(
                "\nAll AddOns are currently up to to date.")
            # message_box.setStandardButtons(QMessageBox.Ok)
            #
            # message_box.exec()

    @pyqtSlot()
    def execute_download(self):
        d = Downloader(self)
        to_update = self.settings.files_to_update

        for addon in to_update:
            print(addon)

        logging.info("Update list: {0}".format(to_update))
        self.LoadingGifSignal.emit(True)
        current_download_val = 1
        download_failed_list = []
        self.window.ui.btnDownloadUpdates.setVisible(False)

        for addon in to_update:
            self.SetUpdateCount.emit(current_download_val, len(to_update))

            if not d.update_addon(addon):
                download_failed_list.append(addon.name)

            self.SetUpdateCount.emit(current_download_val, len(to_update))
            current_download_val += 1

        self.LoadingGifSignal.emit(False)

        # If downloads failed, tell the user.
        if download_failed_list:
            update_text = "The following AddOns failed to download: {0}".format(
                download_failed_list)

            self.MessageBox.emit("Status", update_text, "warn")
        else:
            update_text = "All AddOns were downloaded and extracted successfully to AddOns folder."
            self.MessageBox.emit("Complete", update_text, "inform")

        self.OutputUpdater.emit(update_text)