diff --git a/.gitignore b/.gitignore index 451a286..da85776 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ *.log *.out client/configpcm.ini -client/controltkinter.py BD/database* reports/ __pycache__/ diff --git a/README.MD b/README.MD index 2bc70ca..d988b16 100644 --- a/README.MD +++ b/README.MD @@ -14,10 +14,9 @@ It's not error proof, then, I don't have any responsability if something crashes # Roadmap - Complete translation English and Spanish -- Security (API 1) +- Somewhat more security in API 1 - Stabilize all -- If anyone wants to create a better gui in Python it will be awesome. I used easygui to create a fast usable gui but maybe is not very proffesional.. Anyone? - I had some in TKInter but easygui was very useful without making difficult release it as first usable version +- I created a simple GUI in EasyGUI to be easy used, but maybe I will transition to a web GUI more dynamic and visually better # Requirements diff --git a/api.py b/api.py index 90ae552..cab7019 100644 --- a/api.py +++ b/api.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 BUILD = 16 -API_VER = 0 #Its beta, API 1 will have password checks enabled +API_VER = 1 ##It can be run directly with "waitress-serve --port=3333 api:api" import falcon import random @@ -109,6 +109,12 @@ class getComputers(object): data = sql.select("SELECT * FROM COMPUTERS WHERE ID_C = '"+ComputerID+"')") response.media = data + +## +# getComputersGrp: Know all computers that have a group +# /get/computersgrp? +# @param GroupName/GroupID -> Group to see computers +## class getComputersGrp(object): #List of computers in a group def on_get(self,request, response): logit(request) @@ -182,11 +188,12 @@ class getCookPend(object): # Get the list of cooks for a computer to implement ( # /add/cookgrp? # @param GroupName/GroupID -> Group to show cooks # @param CookName -> Cook to assign +# @param Password -> Password to validate ## class addCookGrp(object): #Assign Cook to group def on_get(self, request, response): logit(request) - GroupID, CookName = None, None # Initialize + GroupID, CookName, Password = None, None, None # Initialize for key, value in request.params.items(): if key == "CookName": exists = os.path.isfile('cooks/'+value+'.yaml') @@ -195,8 +202,12 @@ class addCookGrp(object): #Assign Cook to group GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G']) if key == "GroupID": GroupID = value + if key == "Password" and value == retPassword(): + Password=value if GroupID is None or exists is False: response.media = {'TEXT': 'GroupID is not defined or Cook not exists','RESULT':'ERROR'} + elif Password is None: # Validate password + response.media = {'TEXT': 'Invalid password','RESULT':'ERROR'} elif int(sql.select("SELECT COUNT(*) 'COUNT' FROM COOKS_IDG WHERE `ID_G`='"+GroupID+"' AND `CookName`='"+CookName+"'")[0]['COUNT']) > 0: response.media = {'TEXT': 'This union GROUP-CookName exists','RESULT':'0'} else: @@ -550,7 +561,7 @@ class delComputer(object): #Delete computer class updComputer(object): def on_get(self, request, response): logit(request) - ComputerID, UUID= None, None + ComputerID, UUID, Password= None, None,None for key, value in request.params.items(): if key == "ComputerName": try: @@ -562,6 +573,9 @@ class updComputer(object): ComputerID = value if key == "UUID": UUID = value + if key == "Password" and value == retPassword(): + Password=value + if ComputerID is None and response.media is None: response.media = {'TEXT': 'Error, you need a ComputerName/ComputerID to update data','RESULT':'ERROR'} elif response.media is None and ComputerID is not None and UUID is not None: @@ -590,6 +604,7 @@ class updComputer(object): # /upd/cookname? # @param CookName -> Original Cook Name # @param CookNewName -> New Cook Name +# @param Password -> Password validated command ## class updCookName(object): def on_get(self, request, response): @@ -608,9 +623,13 @@ class updCookName(object): break else: CookNewName= value + if key == "Password" and value == retPassword(): + Password=value if CookName is None or CookNewName is None: response.media = {'TEXT': 'Error, you need the old and new Cook Name to update data','RESULT':'ERROR'} - elif response.media is None: + elif Password is None: # Validate password + response.media = {'TEXT': 'Invalid password','RESULT':'ERROR'} + elif response.media is None: #Like else old_file = os.path.join("cooks", CookName+'.yaml') new_file = os.path.join("cooks", CookNewName+'.yaml') os.rename(old_file, new_file) diff --git a/client/control.ps1 b/client/control.ps1 deleted file mode 100644 index 4bd49d8..0000000 --- a/client/control.ps1 +++ /dev/null @@ -1,320 +0,0 @@ -# Build 2 -Write-Host "This utility is obsolete and may not work. Please use control.pyw" -$root = $PSCommandPath | Split-Path -Parent -$server = (Get-Content "$root\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).server -$resources = (Get-Content "$root\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).resources - - -function seeGroups { - $answer = Invoke-RestMethod -Method Get -Uri "$server/get/groups" - foreach ($st in $answer){ - Write-Host "Grupo:" $st.Name - } -} -function seeComputers { - $answer = Invoke-RestMethod -Method Get -Uri "$server/get/computers" - foreach ($st in $answer){ - Write-Host "Ordenador:" $st.Name - } -} - -function menuReportes { - - do - { - Write-Host "================ Menu reportes ================" - - - Write-Host "1) Reporte de Software" - Write-Host "Q) Salir" - $input = Read-Host "Elegir una Opcion" - switch ($input) - { - '1' { - Clear-Host - . "$PSScriptRoot\ADcomputerData.ps1" - pause - } 'q' { - return - } - } - - } - until ($input -eq 'q') - - -} - -function menuEquipos { - - do - { - Write-Host "================ Menu equipos ================" - - - Write-Host "1) Reporte de Equipos en pantalla" - Write-Host "2) Añadir equipo" - Write-Host "3) Borrar equipo" - Write-Host "4) Añadir equipo a un grupo" - Write-Host "5) Borrar equipo de un grupo" - Write-Host "Q) Salir" - $input = Read-Host "Elegir una Opcion" - switch ($input) - { - '1' { - Clear-Host - seeComputers #Function - pause - } '2' { - Clear-Host - $newHost = Read-Host -Prompt "Nombre del equipo" - if (Test-Connection -ComputerName $newHost -Quiet){ - Write-Output "$newHost Online" - Write-Output "Añadiendo equipo" - Invoke-RestMethod -Method Get -Uri "$server/add/computer?ComputerName=$newHost" - }else{ - Write-Output "$newHost Offline" - } - pause - - } '3' { - Clear-Host - $hhost = Read-Host -Prompt "Nombre del equipo a eliminar" - Invoke-RestMethod -Method Get -Uri "$server/del/computer?ComputerName=$hhost" - } '4' { - Clear-Host - $computer = Read-Host -Prompt "Nombre del equipo" - # See all groups - seeGroups #Function - $newGroup = Read-Host -Prompt "Nombre del grupo a añadir" - Invoke-RestMethod -Method Get -Uri "$server/add/grpcomputer?ComputerName=$computer&GroupName=$newGroup" - pause - } '5' { - Clear-Host - $computer = Read-Host -Prompt "Nombre del equipo" - # See all groups - seeGroups #Function - $newGroup = Read-Host -Prompt "Nombre del grupo a quitar" - Invoke-RestMethod -Method Get -Uri "$server/add/grpcomputer?ComputerName=$computer&GroupName=$newGroup" - pause - } 'q' { - return - } - } - } - until ($input -eq 'q') - - -} - -function menuGrupos { - - do - { - Write-Host "================ Menu grupos ================" - - - Write-Host "1) Reporte de Grupos en pantalla" - Write-Host "2) Ver equipos de un grupo" - Write-Host "3) Añadir grupo" - Write-Host "4) Borrar grupo" - Write-Host "5) Vaciar equipos del grupo" - Write-Host "6) Cambiar nombre del grupo" - Write-Host "7) Ver recetas de un grupo" - Write-Host "Q) Salir" - $input = Read-Host "Elegir una Opción" - switch ($input) - { - '1' { - Clear-Host - seeGroups #Function - pause - } '2' { - Clear-Host - seeGroups - $GroupName = Read-Host -Prompt "Nombre del grupo a ver" - if ($GroupName){ - $answer = Invoke-RestMethod -Method Get -Uri "$server/get/computersgrp?GroupName=$GroupName" - foreach ($st in $answer){ - Write-Host "Ordenador:" $st.Name - } - } - pause - } '3' { - Clear-Host - $newGroup = Read-Host -Prompt "Nombre del grupo a añadir" - Invoke-RestMethod -Method Get -Uri "$server/add/group?GroupName=$newGroup" - pause - - } '4' { - Clear-Host - seeGroups #Function - $grpName = Read-Host -Prompt "Nombre del grupo a eliminar" - Invoke-RestMethod -Method Get -Uri "$server/del/group?GroupName=$grpName" - } '5' { - Clear-Host - seeGroups #Function - $grpName = Read-Host -Prompt "Nombre del grupo a quitar los equipos" - Invoke-RestMethod -Method Get -Uri "$server/del/emptypcsgroup?GroupName=$grpName" - } '6' { - Clear-Host - # See all groups - seeGroups #Function - $GroupName = Read-Host -Prompt "Nombre del grupo" - $GroupNewName = Read-Host -Prompt "Nombre nuevo" - Invoke-RestMethod -Method Get -Uri "$server/upd/group?GroupName=$GroupName&GroupNewName=$GroupNewName" - pause - } '7' { - Clear-Host - # See all groups - seeGroups #Function - $GroupName = Read-Host -Prompt "Nombre del grupo para ver recetas" - if ($GroupName){ - $answer = Invoke-RestMethod -Method Get -Uri "$server/get/cookgrp?GroupName=$GroupName" - foreach ($st in $answer){ - Write-Host "Receta:" $st.CookName - } - }else{ - Write-Host "No hay grupo" - } - pause - } 'q' { - return - } - } - } - until ($input -eq 'q') - -} - - -function menuCooks { - - do - { - Write-Host "================ Menu recetas (Cooks) ================" - - - Write-Host "1) Grupos de una receta" - Write-Host "2) Estado de una receta" - Write-Host "3) Detalles de cada equipo de una receta" - Write-Host "4) Añadir receta a un grupo" - Write-Host "5) Borrar receta de un grupo" - Write-Host "6) Renombrar receta" - Write-Host "Q) Salir" - $input = Read-Host "Elegir una Opción" - switch -regex ($input) - { - '1' { - Clear-Host - $CookName = Read-Host -Prompt "Nombre de la receta" - Write-Host "Grupos de la receta $CookName" - $grpcook = Invoke-RestMethod -Method Get -Uri "$server/get/grpcook?CookName=$CookName" - foreach ($st in $grpcook){ - Write-Host "Grupo:" $st.Name - } - pause - } '2|3' { - Clear-Host - $CookName = Read-Host -Prompt "Nombre de la receta" - - Write-Host "Grupos de la receta" - $grpcook = Invoke-RestMethod -Method Get -Uri "$server/get/grpcook?CookName=$CookName" - foreach ($st in $grpcook){ - Write-Host "Grupo:" $st.Name - } - - $cookrevision = Invoke-RestMethod -Method Get -Uri "$server/get/lastrevisioncook?CookName=$CookName" - $answer = Invoke-RestMethod -Method Get -Uri "$server/get/statuscook?CookName=$CookName" - - if ($_ -eq '3'){ - foreach ($st in $answer){ - Write-Host "Ordenador:" $st.Name ", revision" $st.Revision ", error" $st.Error - } - Write-Host "------Resumen y errores------" - } - $estadistica = @{} - $estadistica.Total = 0 - $estadistica.Error = 0 - $estadistica.NotLast = 0 - foreach ($st in $answer){ - $estadistica.Total++ - if ($st.Error -eq '1'){ - Write-Host "Ordenador en error:" $st.Name - $estadistica.Error++ - } - if ($st.Revision -ne $cookrevision.Revision){ - Write-Host "Ordenador sin la última revisión de la receta:" $st.Name - $estadistica.NotLast++ - } - } - Write-Host "Total implementado:" $estadistica.Total - Write-Host "Errores:" $estadistica.Error - Write-Host "Sin aplicar ultima revisión:" $estadistica.NotLast - pause - } '4' { - Clear-Host - - $CookName = Read-Host -Prompt "Nombre de la receta a añadir" - seeGroups #Function - $GroupName = Read-Host -Prompt "Nombre del grupo que quieres que lo tenga" - Invoke-RestMethod -Method Get -Uri "$server/add/cookgrp?GroupName=$GroupName&CookName=$CookName" - pause - - } '5' { - Clear-Host - $CookName = Read-Host -Prompt "Nombre del receta a eliminar de un grupo" - $grpcook = Invoke-RestMethod -Method Get -Uri "$server/get/grpcook?CookName=$CookName" - foreach ($st in $grpcook){ - Write-Host "Grupo:" $st.Name - } - $GroupName = Read-Host -Prompt "Nombre del grupo" - Invoke-RestMethod -Method Get -Uri "$server/del/cookgrp?GroupName=$GroupName&CookName=$CookName" - pause - } '6' { - Clear-Host - $CookName = Read-Host -Prompt "Nombre del receta actual" - $CookNewName = Read-Host -Prompt "Nuevo nombre" - Invoke-RestMethod -Method Get -Uri "$server/upd/cookname?CookNewName=$CookNewName&CookName=$CookName" - pause - } 'q' { - return - } - } - } - until ($input -eq 'q') - -} - - -do -{ - Write-Host "================ Menú principal ================" - - - Write-Host "1) Reportes" - Write-Host "2) Equipos" - Write-Host "3) Grupos (Locales)" - Write-Host "4) Recetas" - Write-Host "Q) Salir" - $input = Read-Host "Elegir una Opción" - switch ($input) - { - '1' { - Clear-Host - menuReportes - } '2' { - Clear-Host - menuEquipos - } '3' { - Clear-Host - menuGrupos - } '4' { - Clear-Host - menuCooks - } 'q' { - return - } - } -} -until ($input -eq 'q') diff --git a/client/control.pyw b/client/control.pyw index ca8df83..ddd6e85 100644 --- a/client/control.pyw +++ b/client/control.pyw @@ -1,5 +1,5 @@ #!/usr/bin/python3 -# Version 0.61 +# Version 0.7 import easygui import configparser import json @@ -8,6 +8,9 @@ import subprocess, platform import hashlib #SHA256 from translation import T + +passha256 = None # Password (Global) + def ping(host): """ Returns True if host (str) responds to a ping request. @@ -29,8 +32,15 @@ def sendmenudot(text,title,choices): ## showchoicesapi, suburl has to have params (NOT inlcuding server part) def showchoicesapi(text,title,suburl,field='Name'): global c_server + global passha256 + if 'Password=' in suburl: + twopart = "" + elif '?' in suburl: + twopart = '&Password='+str(passha256) + else: + twopart= '?Password='+str(passha256) try: - jsonobj = json.loads(requests.get(c_server+suburl).text) + jsonobj = json.loads(requests.get(c_server+suburl+twopart).text) listitems = [] for ite in jsonobj: listitems.append(ite[field]) @@ -41,8 +51,15 @@ def showchoicesapi(text,title,suburl,field='Name'): def sendsettoapi(suburl,goodtext): # Send a add/del/modify to API. Doesn't return more than "Valid" and "Not valid" global c_server + global passha256 + if 'Password=' in suburl: + twopart = "" + elif '?' in suburl: + twopart = '&Password='+str(passha256) + else: + twopart= '?Password='+str(passha256) try: - jsonobj = json.loads(requests.get(c_server+suburl).text) + jsonobj = json.loads(requests.get(c_server+suburl+twopart).text) #jsonobj['RESULT'] has to exist for next if try: jsonobj['RESULT'] @@ -63,8 +80,15 @@ def sendsettoapi(suburl,goodtext): # Send a add/del/modify to API. Doesn't retur def returnvalueapi(suburl,field="Name"): global c_server + global passha256 + if 'Password=' in suburl: + twopart = "" + elif '?' in suburl: + twopart = '&Password='+str(passha256) + else: + twopart= '?Password='+str(passha256) try: - jsonobj = json.loads(requests.get(c_server+suburl).text) + jsonobj = json.loads(requests.get(c_server+suburl+twopart).text) return jsonobj[field] except: easygui.msgbox(msg='Error en la aplicación al consultar', title="Error", ok_button='OK') diff --git a/doc/example_cooks/remove_program.yaml b/doc/example_cooks/remove_program.yaml index b5c32e1..e889a28 100644 --- a/doc/example_cooks/remove_program.yaml +++ b/doc/example_cooks/remove_program.yaml @@ -2,6 +2,6 @@ name: Remove WinRar as Example revision: 4 steps: - UNINSTALL|WinRAR|This uninstalls WinRAR from Control Panel directly (Powershell powered uninstall) - - NOERROR|Do not fail if this fails + - NOERROR|Do not fail if this fails, for being sure, we will run silent uninstall from default route - CMD|"C:\Program Files\WinRAR\Uninstall.exe" /S - ENDNOERROR|End of never exit if fail \ No newline at end of file diff --git a/doc/naming_limits.md b/doc/naming_limits.md index ea494e1..3f6a36a 100644 --- a/doc/naming_limits.md +++ b/doc/naming_limits.md @@ -1,3 +1,3 @@ -Cooks have to be only alfanumeric caracters and "-","_" and must end with .yaml +Cooks and groups have to be only alfanumeric caracters (a..Z and 0..9) and "-","_" and must end with .yaml -Groups have to be alfanumeric and "-","_" \ No newline at end of file +Do not use simbols or chars like / + $... \ No newline at end of file