mirror of
https://gitlab.com/JKANetwork/powerfulcomputermanager.git
synced 2026-02-19 19:51:31 +01:00
New version with security in transport (https selfsigned), change deps, and preparing web version
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,3 +11,4 @@ __pycache__/
|
|||||||
cooks/*.yaml
|
cooks/*.yaml
|
||||||
control/
|
control/
|
||||||
site/
|
site/
|
||||||
|
admin/
|
||||||
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
# Build 11
|
# Build 13. Using API 2
|
||||||
param([Int32]$startup=0)
|
param([Int32]$startup=0)
|
||||||
#Write-Host $startup
|
#Write-Host $startup
|
||||||
$srcdir = $PSCommandPath | Split-Path -Parent
|
$srcdir = $PSCommandPath | Split-Path -Parent
|
||||||
@@ -9,7 +9,27 @@ $64bit = [Environment]::Is64BitOperatingSystem
|
|||||||
$computerName = [System.Net.Dns]::GetHostName()
|
$computerName = [System.Net.Dns]::GetHostName()
|
||||||
$UUID=(Get-CimInstance Win32_ComputerSystemProduct).UUID
|
$UUID=(Get-CimInstance Win32_ComputerSystemProduct).UUID
|
||||||
|
|
||||||
$exists = Invoke-RestMethod -Method Get -Uri "$server/get/computerexists?ComputerName=$computerName&UUID=$UUID"
|
if ((Get-Host | Select-Object Version).Version.Major -lt 6){#Powershell Windows (Not Core)
|
||||||
|
add-type -TypeDefinition @"
|
||||||
|
using System.Net;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
public class TrustAllCertsPolicy : ICertificatePolicy {
|
||||||
|
public bool CheckValidationResult(
|
||||||
|
ServicePoint srvPoint, X509Certificate certificate,
|
||||||
|
WebRequest request, int certificateProblem) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
|
||||||
|
}else{ # Powershell Core
|
||||||
|
$PSDefaultParameterValues +=
|
||||||
|
@{'Invoke-RestMethod:SkipCertificateCheck' = $true}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$exists = Invoke-RestMethod -Method Post -Uri "$server/get/computerexists?ComputerName=$computerName&UUID=$UUID"
|
||||||
if ($exists.Result -eq "ERROR"){
|
if ($exists.Result -eq "ERROR"){
|
||||||
if ($exists.EXITCODE -eq '3'){
|
if ($exists.EXITCODE -eq '3'){
|
||||||
Write-Host "Computer outside database:" $computerName
|
Write-Host "Computer outside database:" $computerName
|
||||||
@@ -45,25 +65,25 @@ $diskResults = @()
|
|||||||
$ThisVolume.FreeSpace = $([Math]::Round($disk.FreeSpace / 1GB,2))
|
$ThisVolume.FreeSpace = $([Math]::Round($disk.FreeSpace / 1GB,2))
|
||||||
$DiskResults += $ThisVolume
|
$DiskResults += $ThisVolume
|
||||||
}
|
}
|
||||||
$DisksData = $DiskResults |ConvertTo-Json
|
$DisksData = ConvertTo-Json -Depth 4 $DiskResults
|
||||||
$DisksData = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($DisksData)) #I can't enter to database all without encode
|
$DisksData = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($DisksData)) #I can't enter to database all without encode
|
||||||
$lastUser = (Get-CimInstance -ClassName Win32_ComputerSystem -Property UserName -ComputerName .).UserName
|
$lastUser = (Get-CimInstance -ClassName Win32_ComputerSystem -Property UserName -ComputerName .).UserName
|
||||||
# Send it
|
# Send it
|
||||||
$paramInvoke = -join("$server/upd/computer?ComputerName=$computerName&UUID=",$UUID,"&SOVersion=",$SOVersion,"&SOCaption=",$SOData.Caption,"&SOBit=",$SOData.OsArchitecture.Substring(0,2),"&LastConnection=",$Timestamp,"&RAM=",$RAMInstalled,"&RAMFree=",$RAMFree,"&CPUName=",$CPUName,"&LastUser=",$lastUser,"&HDD=",$DisksData)
|
$paramInvoke = -join("$server/upd/computer?ComputerName=$computerName&UUID=",$UUID,"&SOVersion=",$SOVersion,"&SOCaption=",$SOData.Caption,"&SOBit=",$SOData.OsArchitecture.Substring(0,2),"&LastConnection=",$Timestamp,"&RAM=",$RAMInstalled,"&RAMFree=",$RAMFree,"&CPUName=",$CPUName,"&LastUser=",$lastUser,"&HDD=",$DisksData)
|
||||||
Invoke-RestMethod -Method Get -Uri $paramInvoke | out-null
|
Invoke-RestMethod -Method Post -Uri $paramInvoke | out-null
|
||||||
|
|
||||||
# More info (Only if has to be)
|
# More info (Only if has to be)
|
||||||
# $paramInvoke = -join("$server/upd/computerhis?ComputerName=$computerName&UUID=",$UUID,"&RAMFree=",$RAMFree,"&RAMUsed=",$RAMUsed,"&Timestamp=",$Timestamp,"&DisksUse=",$disksUse)
|
# $paramInvoke = -join("$server/upd/computerhis?ComputerName=$computerName&UUID=",$UUID,"&RAMFree=",$RAMFree,"&RAMUsed=",$RAMUsed,"&Timestamp=",$Timestamp,"&DisksUse=",$disksUse)
|
||||||
# Invoke-RestMethod -Method Get -Uri $paramInvoke | out-null
|
# Invoke-RestMethod -Method Post -Uri $paramInvoke | out-null
|
||||||
|
|
||||||
|
|
||||||
# Load Cooks of computer
|
# Load Cooks of computer
|
||||||
$cooks = Invoke-RestMethod -Method Get -Uri "$server/get/cookpend?ComputerName=$computerName&UUID=$UUID"
|
$cooks = Invoke-RestMethod -Method Post -Uri "$server/get/cookpend?ComputerName=$computerName&UUID=$UUID"
|
||||||
|
|
||||||
foreach ($CookName in $cooks){
|
foreach ($CookName in $cooks){
|
||||||
Set-Location $env:temp # For downloading/copying items, use system temp location
|
Set-Location $env:temp # For downloading/copying items, use system temp location
|
||||||
$CookName = $CookName.CookName
|
$CookName = $CookName.CookName
|
||||||
$cook = Invoke-RestMethod -Method Get -Uri "$server/load/cook?CookName=$CookName&ComputerName=$computerName&UUID=$UUID"
|
$cook = Invoke-RestMethod -Method Post -Uri "$server/load/cook?CookName=$CookName&ComputerName=$computerName&UUID=$UUID"
|
||||||
Write-Host "Receta:" $cook.name
|
Write-Host "Receta:" $cook.name
|
||||||
$CookRevision = $cook.revision
|
$CookRevision = $cook.revision
|
||||||
$atstartup = $cook.atstartup
|
$atstartup = $cook.atstartup
|
||||||
@@ -261,7 +281,7 @@ foreach ($CookName in $cooks){
|
|||||||
if ($cook.runever -eq "1"){
|
if ($cook.runever -eq "1"){
|
||||||
$err = -1 # This is for run but not for error, is by cook saw.
|
$err = -1 # This is for run but not for error, is by cook saw.
|
||||||
}
|
}
|
||||||
Invoke-RestMethod -Method Get -Uri "$server/upd/cookstatus?ComputerName=$computerName&UUID=$UUID&CookName=$CookName&Revision=$CookRevision&Error=$err&ErrorDesc=$errvar" | out-null
|
Invoke-RestMethod -Method Post -Uri "$server/set/cookstatus?ComputerName=$computerName&UUID=$UUID&CookName=$CookName&Revision=$CookRevision&Error=$err&ErrorDesc=$errvar" | out-null
|
||||||
|
|
||||||
#Delete files copied to temp for saving space
|
#Delete files copied to temp for saving space
|
||||||
foreach ($element in $filesCopied) {
|
foreach ($element in $filesCopied) {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
server=http://miserver.dominio:3333
|
server=https://miserver.dominio:3333
|
||||||
resources=\\\\MISERVER\\REPOFOLDER
|
resources=\\\\MISERVER\\REPOFOLDER
|
||||||
lang=en
|
lang=en
|
||||||
@@ -12,6 +12,13 @@ from translation import T
|
|||||||
|
|
||||||
passha256 = None # Password (Global)
|
passha256 = None # Password (Global)
|
||||||
|
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read('configpcm.ini')
|
||||||
|
|
||||||
|
c_server = config['General']['server']
|
||||||
|
c_resources = config['General']['resources'].replace('\\\\','\\')
|
||||||
|
|
||||||
|
|
||||||
def ping(host):
|
def ping(host):
|
||||||
"""
|
"""
|
||||||
Returns True if host (str) responds to a ping request.
|
Returns True if host (str) responds to a ping request.
|
||||||
@@ -30,6 +37,10 @@ def sendmenudot(text,title,choices):
|
|||||||
return menu.split('.')[0]
|
return menu.split('.')[0]
|
||||||
else:
|
else:
|
||||||
return menu
|
return menu
|
||||||
|
|
||||||
|
def retOpt(option):
|
||||||
|
return returnvalueapi('/get/optionvalue?Option='+str(option),field="Value")
|
||||||
|
|
||||||
## showchoicesapi, suburl has to have params (NOT inlcuding server part)
|
## showchoicesapi, suburl has to have params (NOT inlcuding server part)
|
||||||
def showchoicesapi(text,title,suburl,field=['Name']):
|
def showchoicesapi(text,title,suburl,field=['Name']):
|
||||||
global c_server
|
global c_server
|
||||||
@@ -43,7 +54,8 @@ def showchoicesapi(text,title,suburl,field=['Name']):
|
|||||||
else:
|
else:
|
||||||
twopart= '?Password='+str(passha256)
|
twopart= '?Password='+str(passha256)
|
||||||
try:
|
try:
|
||||||
jsonobj = json.loads(requests.get(c_server+suburl+twopart).text)
|
r=(requests.post(c_server+suburl+twopart, verify=False).text).replace("\'", "\"").replace('\\"',"'").replace(': None',': "None"')
|
||||||
|
jsonobj = json.loads(r)
|
||||||
listitems = []
|
listitems = []
|
||||||
for ite in jsonobj: # Run in array from json
|
for ite in jsonobj: # Run in array from json
|
||||||
to = ""
|
to = ""
|
||||||
@@ -66,8 +78,8 @@ def sendsettoapi(suburl,goodtext): # Send a add/del/modify to API. Doesn't retur
|
|||||||
else:
|
else:
|
||||||
twopart= '?Password='+str(passha256)
|
twopart= '?Password='+str(passha256)
|
||||||
try:
|
try:
|
||||||
jsonobj = json.loads(requests.get(c_server+suburl+twopart).text)
|
r=(requests.post(c_server+suburl+twopart, verify=False).text).replace("\'", "\"").replace('\\"',"'").replace(': None',': "None"')
|
||||||
#jsonobj['RESULT'] has to exist for next if
|
jsonobj = json.loads(r)
|
||||||
try:
|
try:
|
||||||
jsonobj['RESULT']
|
jsonobj['RESULT']
|
||||||
except:
|
except:
|
||||||
@@ -95,22 +107,16 @@ def returnvalueapi(suburl,field="Name"):
|
|||||||
else:
|
else:
|
||||||
twopart= '?Password='+str(passha256)
|
twopart= '?Password='+str(passha256)
|
||||||
try:
|
try:
|
||||||
jsonobj = json.loads(requests.get(c_server+suburl+twopart).text)
|
r=(requests.post(c_server+suburl+twopart, verify=False).text).replace("\'", "\"").replace('\\"',"'").replace(': None',': "None"')
|
||||||
|
jsonobj = json.loads(r)
|
||||||
return jsonobj[field]
|
return jsonobj[field]
|
||||||
except:
|
except:
|
||||||
easygui.msgbox(msg=T('Error talking with API'), title="Error", ok_button='OK')
|
easygui.msgbox(msg=T('Error talking with API'), title="Error", ok_button='OK')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
config.read('configpcm.ini')
|
|
||||||
|
|
||||||
c_server = config['General']['server']
|
|
||||||
c_resources = config['General']['resources'].replace('\\\\','\\')
|
|
||||||
|
|
||||||
|
|
||||||
def menuprinc():
|
def menuprinc():
|
||||||
menu = sendmenudot(T('Main menu'),T('Select option'),['1.'+T('Computers'),'2.'+T('Groups'),'3.'+T('Cooks'),'4.Reportes/Listados'])
|
menu = sendmenudot(T('Main menu'),T('Select option'),['1.'+T('Computers'),'2.'+T('Groups'),'3.'+T('Cooks'),'4.Reportes/Listados','5.'+T('Options')])
|
||||||
if menu == '1':
|
if menu == '1':
|
||||||
mcomputers()
|
mcomputers()
|
||||||
elif menu == '2':
|
elif menu == '2':
|
||||||
@@ -119,6 +125,8 @@ def menuprinc():
|
|||||||
mcooks()
|
mcooks()
|
||||||
elif menu == '4':
|
elif menu == '4':
|
||||||
mreports()
|
mreports()
|
||||||
|
elif menu == '5':
|
||||||
|
moptions()
|
||||||
|
|
||||||
def mcomputers():
|
def mcomputers():
|
||||||
menu = sendmenudot(T('Computers menu'),T('Select option'),['1.'+T('Add computer'),'2.'+T('Remove computer'),'3.'+T('Add computer to group'),'4.'+T('Computers list'),'5.'+T('Computer status')])
|
menu = sendmenudot(T('Computers menu'),T('Select option'),['1.'+T('Add computer'),'2.'+T('Remove computer'),'3.'+T('Add computer to group'),'4.'+T('Computers list'),'5.'+T('Computer status')])
|
||||||
@@ -177,7 +185,8 @@ def mcooks():
|
|||||||
cook = showchoicesapi("Lista de recetas implementadas en algún grupo. Selecciona una para ver sus datos","Detalles de una receta","/get/cookall",'CookName')
|
cook = showchoicesapi("Lista de recetas implementadas en algún grupo. Selecciona una para ver sus datos","Detalles de una receta","/get/cookall",'CookName')
|
||||||
if cook is not None:
|
if cook is not None:
|
||||||
showchoicesapi("Lista de grupos de la receta "+cook,"Listado de grupos de una receta","/get/grpcook?CookName="+cook)
|
showchoicesapi("Lista de grupos de la receta "+cook,"Listado de grupos de una receta","/get/grpcook?CookName="+cook)
|
||||||
jsonobj = json.loads(requests.get(c_server+'/get/statuscook?CookName='+cook).text)
|
r=(requests.post(c_server+'/get/statuscook?CookName='+cook, verify=False).text).replace("\'", "\"").replace('\\"',"'").replace(': None',': "None"')
|
||||||
|
jsonobj = json.loads(r)
|
||||||
list = []
|
list = []
|
||||||
s_err = 0
|
s_err = 0
|
||||||
s_com = 0
|
s_com = 0
|
||||||
@@ -248,6 +257,20 @@ def mreports():
|
|||||||
return
|
return
|
||||||
mreports()
|
mreports()
|
||||||
|
|
||||||
|
def moptions():
|
||||||
|
debugsql = retOpt('DebugSQL')
|
||||||
|
addcomputers = retOpt('AddComputers')
|
||||||
|
menu = sendmenudot(T('Options menu'),T('Select option'),['1.'+T('Debug SQL commands')+'-'+str(debugsql),'2.'+T('Allow auto add of new computers')+'-'+str(addcomputers)])
|
||||||
|
|
||||||
|
if menu == '1':
|
||||||
|
showchoicesapi(T('Computers list'),T('Computers list'),"/get/computers")
|
||||||
|
elif menu == '2':
|
||||||
|
showchoicesapi(T('Groups list'),T('Groups list'),"/get/groups")
|
||||||
|
elif menu is None:
|
||||||
|
menuprinc()
|
||||||
|
return
|
||||||
|
mreports()
|
||||||
|
|
||||||
|
|
||||||
def m_addcomputergroup():
|
def m_addcomputergroup():
|
||||||
whatc = showchoicesapi(T('Select computer to add to a group'),T('Add computer to group'),"/get/computers")
|
whatc = showchoicesapi(T('Select computer to add to a group'),T('Add computer to group'),"/get/computers")
|
||||||
@@ -272,6 +295,7 @@ def m_delcomputergroup():
|
|||||||
|
|
||||||
# Check password before starting all
|
# Check password before starting all
|
||||||
pa = returnvalueapi("/check/password?Password=None",field="EXITCODE")
|
pa = returnvalueapi("/check/password?Password=None",field="EXITCODE")
|
||||||
|
print(pa)
|
||||||
if pa == "3": # No password stored yet
|
if pa == "3": # No password stored yet
|
||||||
passw = easygui.passwordbox(T('There is no password yet in PCM. Please set one below'),T('Set password'))
|
passw = easygui.passwordbox(T('There is no password yet in PCM. Please set one below'),T('Set password'))
|
||||||
passw2 = easygui.passwordbox(T('Confirm it'),T('Set password'))
|
passw2 = easygui.passwordbox(T('Confirm it'),T('Set password'))
|
||||||
@@ -292,6 +316,7 @@ else: # There is a password
|
|||||||
quit()
|
quit()
|
||||||
passha256 = hashlib.sha256(passw.encode()).hexdigest()
|
passha256 = hashlib.sha256(passw.encode()).hexdigest()
|
||||||
re = returnvalueapi("/check/password?Password="+passha256,field="EXITCODE") # Create password in database
|
re = returnvalueapi("/check/password?Password="+passha256,field="EXITCODE") # Create password in database
|
||||||
|
print(re)
|
||||||
if re == '0': # Password is right
|
if re == '0': # Password is right
|
||||||
menuprinc()
|
menuprinc()
|
||||||
else:
|
else:
|
||||||
|
|||||||
10
docs/changelog.md
Normal file
10
docs/changelog.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2019/11/20
|
||||||
|
- New API (2). All requests now works in POST and SSL (Self-Signed)
|
||||||
|
- Now using Flask and not falcon with waitress-serve (Lesser dependencies and ssl support)
|
||||||
|
- Some new options
|
||||||
|
- More stable (Besides this API is at beta stage because POST and different json returns)
|
||||||
|
- Better doc
|
||||||
|
- Preparing for better gui (Web one)
|
||||||
|
- Now SQL will have versions, for updating if neccesary (If you are using old version, please create in database new table "OPTIONS" with data that has "emptydatabase.db")
|
||||||
@@ -14,7 +14,6 @@ It's not error proof, then, I don't have any responsability if something crashes
|
|||||||
# Roadmap
|
# Roadmap
|
||||||
|
|
||||||
- Complete translation English and Spanish
|
- Complete translation English and Spanish
|
||||||
- Somewhat more security in API 1
|
|
||||||
- Stabilize all
|
- Stabilize all
|
||||||
- I created a simple GUI in EasyGUI to be easy used, but if I have time, maybe will do a webUI more dynamic and visually better (Without needing to install php/apache/nginx, using python)
|
- I created a simple GUI in EasyGUI to be easy used, but if I have time, maybe will do a webUI more dynamic and visually better (Without needing to install php/apache/nginx, using python)
|
||||||
- Support Linux clients
|
- Support Linux clients
|
||||||
@@ -22,12 +21,12 @@ It's not error proof, then, I don't have any responsability if something crashes
|
|||||||
# Requirements
|
# Requirements
|
||||||
|
|
||||||
## Server
|
## Server
|
||||||
For server you can use Linux or Windows, and in theory any environment that can run Python 3 can work as server
|
For server you can use Linux, Mac or Windows, and in theory any environment that can run Python 3 can work as server
|
||||||
- Python3 with:
|
- Python3 with:
|
||||||
- Falcon
|
- Flask
|
||||||
- Waitress-serve
|
- pyopenssl
|
||||||
- Yaml
|
- Yaml
|
||||||
Python3 deps can be installed it using pip install command (pip install waitress falcon pyyaml)
|
Python3 deps can be installed it using pip install command (pip install pyopenssl flask pyyaml)
|
||||||
- For controlling the program, you have to start control.pyw using Python3. It doesn't need to be started in server, but it has to be in that folder (Or with configpcm.ini file).
|
- For controlling the program, you have to start control.pyw using Python3. It doesn't need to be started in server, but it has to be in that folder (Or with configpcm.ini file).
|
||||||
It uses easygui of python3 (pip install easygui)
|
It uses easygui of python3 (pip install easygui)
|
||||||
|
|
||||||
@@ -47,7 +46,6 @@ For server you can use Linux or Windows, and in theory any environment that can
|
|||||||
## Server
|
## Server
|
||||||
- Copy this folder to a folder in your server
|
- Copy this folder to a folder in your server
|
||||||
- Install dependencies
|
- Install dependencies
|
||||||
- Open sysopt.py file and change values if needed
|
|
||||||
- Start the server: Start api.py using loadserver.bat (Windows) o loadserver.sh (Linux) file. You can do in systemd way, or a cron, or in a terminal of windows server,...
|
- Start the server: Start api.py using loadserver.bat (Windows) o loadserver.sh (Linux) file. You can do in systemd way, or a cron, or in a terminal of windows server,...
|
||||||
|
|
||||||
## Client. Example using GPO and Task Schedule
|
## Client. Example using GPO and Task Schedule
|
||||||
@@ -66,4 +64,4 @@ For server you can use Linux or Windows, and in theory any environment that can
|
|||||||
- Args: -executionpolicy bypass -windowstyle hidden -noninteractive -nologo -file "\\SERVER\SysVol\DOMAINNAME\scripts\client.ps1" -startup 1
|
- Args: -executionpolicy bypass -windowstyle hidden -noninteractive -nologo -file "\\SERVER\SysVol\DOMAINNAME\scripts\client.ps1" -startup 1
|
||||||
|
|
||||||
## Control app
|
## Control app
|
||||||
- Start control.pyw to setup password and start adding computers, groups and cooks. You can use docs/example_cooks for examples. If anyone wants, I will setup a git repo for cooks.
|
- Start control.pyw to setup password and start adding computers, groups and cooks and configure options. You can use docs/example_cooks for examples. If anyone wants, I will setup a git repo for cooks.
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
REM Starting Server. Will only work if python and dependencies are installed and in PATH
|
REM Starting Server. Will only work if python and dependencies are installed and in PATH
|
||||||
cd /D "%~dp0"
|
cd /D "%~dp0"
|
||||||
waitress-serve --port=3333 api:api
|
python3 api.py
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd "$(dirname "$(realpath "$0")")";
|
cd "$(dirname "$(realpath "$0")")";
|
||||||
waitress-serve --port=3333 api:api
|
python3 api.py
|
||||||
@@ -4,4 +4,5 @@ nav:
|
|||||||
- Quick Start: quick_start.md
|
- Quick Start: quick_start.md
|
||||||
- How to write a cook: howto_writecook.md
|
- How to write a cook: howto_writecook.md
|
||||||
- Hierarchy: file_hierarchy.md
|
- Hierarchy: file_hierarchy.md
|
||||||
|
- Changelog: changelog.md
|
||||||
theme: readthedocs
|
theme: readthedocs
|
||||||
Reference in New Issue
Block a user