Build and package ogagent py3/qt6 for windows and linux #2
|
@ -11,10 +11,20 @@ linux/debian/ogagent.postinst.debhelper
|
|||
linux/debian/ogagent.postrm.debhelper
|
||||
linux/configure-stamp
|
||||
linux/build-stamp
|
||||
macos/build
|
||||
windows/vc_redist.x64.exe
|
||||
ogagent_*_all.deb
|
||||
ogagent_*_amd64.buildinfo
|
||||
ogagent_*_amd64.changes
|
||||
ogagent_*_amd64.build
|
||||
OGAgentInstaller-*.pkg
|
||||
OGAgentSetup-*.exe
|
||||
bin
|
||||
src/build
|
||||
src/dist
|
||||
src/about_dialog_ui.py
|
||||
src/message_dialog_ui.py
|
||||
src/OGAgent_rc.py
|
||||
src/dist
|
||||
src/build
|
||||
windows/VERSION
|
||||
windows/VC_redist.x64.exe
|
||||
|
|
|
@ -39,7 +39,6 @@ install-ogagent:
|
|||
cp $(SOURCEDIR)/OGAgentUser.py $(LIBDIR)
|
||||
# QT Dialogs & resources
|
||||
cp $(SOURCEDIR)/*_ui.py $(LIBDIR)
|
||||
cp $(SOURCEDIR)/OGAgent_rc.py $(LIBDIR)
|
||||
# Version file
|
||||
cp $(SOURCEDIR)/VERSION $(LIBDIR)
|
||||
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
ogagent (1.3.1-1) stable; urgency=medium
|
||||
|
||||
* Migrate the update script from shell to python
|
||||
* pyinstaller: include the 'img' subdir
|
||||
* take icons from 'img'
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Wed, 26 Jun 2024 15:16:57 +0200
|
||||
|
||||
ogagent (1.3.0-2) stable; urgency=medium
|
||||
|
||||
* Add missing dependency on zenity
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#!/bin/bash
|
||||
# Create macOS installation packages.
|
||||
# Based on bomutils tutorail: http://bomutils.dyndns.org/tutorial.html
|
||||
# Based on bomutils tutorial: http://bomutils.dyndns.org/tutorial.html
|
||||
|
||||
cd $(dirname $0)
|
||||
[ -r ../src/VERSION ] && VERSION="$(cat ../src/VERSION)" || VERSION="1.1.0"
|
||||
[ -r ../src/VERSION ] && VERSION="$(cat ../src/VERSION)" || (echo "Can't get version from ../src/VERSION" 1>&2; exit 1)
|
||||
AUTHOR="OpenGnsys Project"
|
||||
|
||||
# Create empty directories.
|
||||
|
@ -12,8 +12,8 @@ mkdir -p build && cd build
|
|||
mkdir -p flat/base.pkg flat/Resources/en.lproj
|
||||
mkdir -p root/Applications
|
||||
|
||||
# Copy application and script files.
|
||||
cp -a ../../src root/Applications/OGAgent.app
|
||||
# Copy application and script files. Exclude 'test_modules'
|
||||
cp -a ../../src root/Applications/OGAgent.app; rm -rf root/Applications/OGAgent.app/test_modules
|
||||
cp -a ../scripts .
|
||||
|
||||
# Create plist file.
|
||||
|
@ -84,4 +84,3 @@ EOT
|
|||
# Create new Xar application archive.
|
||||
rm -f ../../../OGAgentInstaller-$VERSION.pkg
|
||||
( cd flat && xar --compression none -cf "../../../OGAgentInstaller-$VERSION.pkg" * )
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>es.opengnsys.ogagent</string>
|
||||
<string>es.opengnsys.agent.system</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/bin/ogagent</string>
|
||||
<string>/usr/local/bin/ogagent</string>
|
||||
<string>start</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>es.opengnsys.agent.user</string>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>/usr/local/bin:/usr/bin:/bin</string>
|
||||
</dict>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Applications/OGAgent.app</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Applications/OGAgent.app/OGAgentUser.py</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,832 @@
|
|||
#!/usr/bin/env python3
|
||||
# encoding: utf8
|
||||
|
||||
"""
|
||||
This program is taken from https://github.com/brona/iproute2mac
|
||||
When doing 'brew install iproute2mac', we get an old version (1.4.2) that doesn't support 'ip -json'
|
||||
The alternative installation method recomended in the project's README file is 'curl; chmod; mv'
|
||||
Therefore we make the decision of shipping this ip.py (version 1.5.0) along opengnsys, which is pretty much the same as curling it
|
||||
"""
|
||||
|
||||
|
||||
"""
|
||||
iproute2mac
|
||||
CLI wrapper for basic network utilites on Mac OS X.
|
||||
Homepage: https://github.com/brona/iproute2mac
|
||||
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2015 Bronislav Robenek <brona@robenek.me>
|
||||
"""
|
||||
|
||||
import ipaddress
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import socket
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import types
|
||||
|
||||
# Version
|
||||
VERSION = "1.5.0"
|
||||
|
||||
# Utilities
|
||||
SUDO = "/usr/bin/sudo"
|
||||
IFCONFIG = "/sbin/ifconfig"
|
||||
ROUTE = "/sbin/route"
|
||||
NETSTAT = "/usr/sbin/netstat"
|
||||
NDP = "/usr/sbin/ndp"
|
||||
ARP = "/usr/sbin/arp"
|
||||
NETWORKSETUP = "/usr/sbin/networksetup"
|
||||
|
||||
|
||||
# Helper functions
|
||||
def perror(*args):
|
||||
sys.stderr.write(*args)
|
||||
sys.stderr.write("\n")
|
||||
|
||||
|
||||
def execute_cmd(cmd):
|
||||
print("Executing: %s" % cmd)
|
||||
status, output = subprocess.getstatusoutput(cmd)
|
||||
if status == 0: # unix/linux commands 0 true, 1 false
|
||||
print(output)
|
||||
return True
|
||||
else:
|
||||
perror(output)
|
||||
return False
|
||||
|
||||
|
||||
def json_dump(data, pretty):
|
||||
if pretty:
|
||||
print(json.dumps(data, indent=4))
|
||||
else:
|
||||
print(json.dumps(data, separators=(",", ":")))
|
||||
return True
|
||||
|
||||
# Classful to CIDR conversion with "default" being passed through
|
||||
def cidr_from_netstat_dst(target):
|
||||
if target == "default":
|
||||
return target
|
||||
|
||||
dots = target.count(".")
|
||||
if target.find("/") == -1:
|
||||
addr = target
|
||||
netmask = (dots + 1) * 8
|
||||
else:
|
||||
[addr, netmask] = target.split("/")
|
||||
|
||||
addr = addr + ".0" * (3 - dots)
|
||||
return addr + "/" + str(netmask)
|
||||
|
||||
|
||||
# Convert hexadecimal netmask in prefix length
|
||||
def netmask_to_length(mask):
|
||||
return int(mask, 16).bit_count()
|
||||
|
||||
|
||||
def any_startswith(words, test):
|
||||
for word in words:
|
||||
if word.startswith(test):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# Handles passsing return value, error messages and program exit on error
|
||||
def help_msg(help_func):
|
||||
def wrapper(func):
|
||||
def inner(*args, **kwargs):
|
||||
if not func(*args, **kwargs):
|
||||
specific = eval(help_func)
|
||||
if specific:
|
||||
if isinstance(specific, types.FunctionType):
|
||||
if args and kwargs:
|
||||
specific(*args, **kwargs)
|
||||
else:
|
||||
specific()
|
||||
return False
|
||||
else:
|
||||
raise Exception("Function expected for: " + help_func)
|
||||
else:
|
||||
raise Exception(
|
||||
"Function variant not defined: " + help_func
|
||||
)
|
||||
return True
|
||||
|
||||
return inner
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
# Generate random MAC address with XenSource Inc. OUI
|
||||
# http://www.linux-kvm.com/sites/default/files/macgen.py
|
||||
def randomMAC():
|
||||
mac = [
|
||||
0x00,
|
||||
0x16,
|
||||
0x3E,
|
||||
random.randint(0x00, 0x7F),
|
||||
random.randint(0x00, 0xFF),
|
||||
random.randint(0x00, 0xFF),
|
||||
]
|
||||
return ":".join(["%02x" % x for x in mac])
|
||||
|
||||
|
||||
# Decode ifconfig output
|
||||
def parse_ifconfig(res, af, address):
|
||||
links = []
|
||||
count = 1
|
||||
|
||||
for r in res.split("\n"):
|
||||
if re.match(r"^\w+:", r):
|
||||
if count > 1:
|
||||
links.append(link)
|
||||
(ifname, flags, mtu, ifindex) = re.findall(r"^(\w+): flags=\d+<(.*)> mtu (\d+) index (\d+)", r)[0]
|
||||
flags = flags.split(",")
|
||||
link = {
|
||||
"ifindex": int(ifindex),
|
||||
"ifname": ifname,
|
||||
"flags": flags,
|
||||
"mtu": int(mtu),
|
||||
"operstate": "UNKNOWN",
|
||||
"link_type": "unknown"
|
||||
}
|
||||
if "LOOPBACK" in flags:
|
||||
link["link_type"] = "loopback"
|
||||
link["address"] = "00:00:00:00:00:00"
|
||||
link["broadcast"] = "00:00:00:00:00:00"
|
||||
elif "POINTOPOINT" in flags:
|
||||
link["link_type"] = "none"
|
||||
count = count + 1
|
||||
else:
|
||||
if re.match(r"^\s+ether ", r):
|
||||
link["link_type"] = "ether"
|
||||
link["address"] = re.findall(r"(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)", r)[0]
|
||||
link["broadcast"] = "ff:ff:ff:ff:ff:ff"
|
||||
elif address and re.match(r"^\s+inet ", r) and af != 6:
|
||||
(local, netmask) = re.findall(r"inet (\d+\.\d+\.\d+\.\d+) netmask (0x[0-9a-f]+)", r)[0]
|
||||
addr = {
|
||||
"family": "inet",
|
||||
"local": local,
|
||||
"prefixlen": netmask_to_length(netmask),
|
||||
}
|
||||
if re.match(r"^.*broadcast", r):
|
||||
addr["broadcast"] = re.findall(r"broadcast (\d+\.\d+\.\d+\.\d+)", r)[0]
|
||||
link["addr_info"] = link.get("addr_info", []) + [addr]
|
||||
elif address and re.match(r"^\s+inet6 ", r) and af != 4:
|
||||
(local, prefixlen) = re.findall(r"inet6 ((?:[a-f0-9:]+:+)+[a-f0-9]+)%*\w* +prefixlen (\d+)", r)[0]
|
||||
link["addr_info"] = link.get("addr_info", []) + [{
|
||||
"family": "inet6",
|
||||
"local": local,
|
||||
"prefixlen": int(prefixlen)
|
||||
}]
|
||||
elif re.match(r"^\s+status: ", r):
|
||||
match re.findall(r"status: (\w+)", r)[0]:
|
||||
case "active":
|
||||
link["operstate"] = "UP"
|
||||
case "inactive":
|
||||
link["operstate"] = "DOWN"
|
||||
|
||||
if count > 1:
|
||||
links.append(link)
|
||||
|
||||
return links
|
||||
|
||||
|
||||
def link_addr_show(argv, af, json_print, pretty_json, address):
|
||||
if len(argv) > 0 and argv[0] == "dev":
|
||||
argv.pop(0)
|
||||
if len(argv) > 0:
|
||||
param = argv[0]
|
||||
else:
|
||||
param = "-a"
|
||||
|
||||
status, res = subprocess.getstatusoutput(
|
||||
IFCONFIG + " -v " + param + " 2>/dev/null"
|
||||
)
|
||||
if status: # unix status
|
||||
if res == "":
|
||||
perror(param + " not found")
|
||||
else:
|
||||
perror(res)
|
||||
return False
|
||||
|
||||
links = parse_ifconfig(res, af, address)
|
||||
|
||||
if json_print:
|
||||
return json_dump(links, pretty_json)
|
||||
|
||||
for l in links:
|
||||
print("%d: %s: <%s> mtu %d status %s" % (
|
||||
l["ifindex"], l["ifname"], ",".join(l["flags"]), l["mtu"], l["operstate"]
|
||||
))
|
||||
print(
|
||||
" link/" + l["link_type"] +
|
||||
((" " + l["address"]) if "address" in l else "") +
|
||||
((" brd " + l["broadcast"]) if "broadcast" in l else "")
|
||||
)
|
||||
for a in l.get("addr_info", []):
|
||||
print(
|
||||
" %s %s/%d" % (a["family"], a["local"], a["prefixlen"]) +
|
||||
((" brd " + a["broadcast"]) if "broadcast" in a else "")
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# Help
|
||||
def do_help(argv=None, af=None, json_print=None, pretty_json=None):
|
||||
perror("Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }")
|
||||
perror("where OBJECT := { link | addr | route | neigh }")
|
||||
perror(" OPTIONS := { -V[ersion] | -j[son] | -p[retty] |")
|
||||
perror(" -4 | -6 }")
|
||||
perror("iproute2mac")
|
||||
perror("Homepage: https://github.com/brona/iproute2mac")
|
||||
perror(
|
||||
"This is CLI wrapper for basic network utilities on Mac OS X"
|
||||
" inspired with iproute2 on Linux systems."
|
||||
)
|
||||
perror(
|
||||
"Provided functionality is limited and command output is not"
|
||||
" fully compatible with iproute2."
|
||||
)
|
||||
perror(
|
||||
"For advanced usage use netstat, ifconfig, ndp, arp, route "
|
||||
" and networksetup directly."
|
||||
)
|
||||
exit(255)
|
||||
|
||||
|
||||
def do_help_route():
|
||||
perror("Usage: ip route list")
|
||||
perror(" ip route get ADDRESS")
|
||||
perror(" ip route { add | del | replace } ROUTE")
|
||||
perror(" ip route flush cache")
|
||||
perror(" ip route flush table main")
|
||||
perror("ROUTE := NODE_SPEC [ INFO_SPEC ]")
|
||||
perror("NODE_SPEC := [ TYPE ] PREFIX")
|
||||
perror("INFO_SPEC := NH")
|
||||
perror("TYPE := { blackhole }")
|
||||
perror("NH := { via ADDRESS | gw ADDRESS | nexthop ADDRESS | dev STRING }")
|
||||
exit(255)
|
||||
|
||||
|
||||
def do_help_addr():
|
||||
perror("Usage: ip addr show [ dev STRING ]")
|
||||
perror(" ip addr { add | del } PREFIX dev STRING")
|
||||
exit(255)
|
||||
|
||||
|
||||
def do_help_link():
|
||||
perror("Usage: ip link show [ DEVICE ]")
|
||||
perror(" ip link set dev DEVICE")
|
||||
perror(" [ { up | down } ]")
|
||||
perror(" [ address { LLADDR | factory | random } ]")
|
||||
perror(" [ mtu MTU ]")
|
||||
exit(255)
|
||||
|
||||
|
||||
def do_help_neigh():
|
||||
perror("Usage: ip neighbour show [ [ to ] PREFIX ] [ dev DEV ]")
|
||||
perror(" ip neighbour flush [ dev DEV ]")
|
||||
exit(255)
|
||||
|
||||
|
||||
# Route Module
|
||||
@help_msg("do_help_route")
|
||||
def do_route(argv, af, json_print, pretty_json):
|
||||
if not argv or (
|
||||
any_startswith(["show", "lst", "list"], argv[0]) and len(argv) == 1
|
||||
):
|
||||
return do_route_list(af, json_print, pretty_json)
|
||||
elif "get".startswith(argv[0]) and len(argv) == 2:
|
||||
argv.pop(0)
|
||||
return do_route_get(argv, af, json_print, pretty_json)
|
||||
elif "add".startswith(argv[0]) and len(argv) >= 3:
|
||||
argv.pop(0)
|
||||
return do_route_add(argv, af)
|
||||
elif "delete".startswith(argv[0]) and len(argv) >= 2:
|
||||
argv.pop(0)
|
||||
return do_route_del(argv, af)
|
||||
elif "replace".startswith(argv[0]) and len(argv) >= 3:
|
||||
argv.pop(0)
|
||||
return do_route_del(argv, af) and do_route_add(argv, af)
|
||||
elif "flush".startswith(argv[0]) and len(argv) >= 1:
|
||||
argv.pop(0)
|
||||
return do_route_flush(argv, af)
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def do_route_list(af, json_print, pretty_json):
|
||||
# ip route prints IPv6 or IPv4, never both
|
||||
inet = "inet6" if af == 6 else "inet"
|
||||
status, res = subprocess.getstatusoutput(
|
||||
NETSTAT + " -nr -f " + inet + " 2>/dev/null"
|
||||
)
|
||||
if status:
|
||||
perror(res)
|
||||
return False
|
||||
res = res.split("\n")
|
||||
res = res[4:] # Removes first 4 lines
|
||||
|
||||
routes = []
|
||||
|
||||
for r in res:
|
||||
ra = r.split()
|
||||
target = ra[0]
|
||||
gw = ra[1]
|
||||
flags = ra[2]
|
||||
# macOS Mojave and earlier vs Catalina
|
||||
dev = ra[5] if len(ra) >= 6 else ra[3]
|
||||
if flags.find("W") != -1:
|
||||
continue
|
||||
if af == 6:
|
||||
target = re.sub(r"%[^ ]+/", "/", target)
|
||||
else:
|
||||
target = cidr_from_netstat_dst(target)
|
||||
if flags.find("B") != -1:
|
||||
routes.append({"type": "blackhole", "dst": target, "flags": []})
|
||||
continue
|
||||
if re.match(r"link.+", gw):
|
||||
routes.append({"dst": target, "dev": dev, "scope": "link", "flags": []})
|
||||
else:
|
||||
routes.append({"dst": target, "gateway": gw, "dev": dev, "flags": []})
|
||||
|
||||
if json_print:
|
||||
return json_dump(routes, pretty_json)
|
||||
|
||||
for route in routes:
|
||||
if "type" in route:
|
||||
print("%s %s" % (route["type"], route["dst"]))
|
||||
elif "scope" in route:
|
||||
print("%s dev %s scope %s" % (route["dst"], route["dev"], route["scope"]))
|
||||
elif "gateway" in route:
|
||||
print("%s via %s dev %s" % (route["dst"], route["gateway"], route["dev"]))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def do_route_add(argv, af):
|
||||
options = ""
|
||||
if argv[0] == "blackhole":
|
||||
argv.pop(0)
|
||||
if len(argv) != 1:
|
||||
return False
|
||||
argv.append("via")
|
||||
argv.append("::1" if ":" in argv[0] or af == 6 else "127.0.0.1")
|
||||
options = "-blackhole"
|
||||
|
||||
if len(argv) not in (3, 5):
|
||||
return False
|
||||
|
||||
if len(argv) == 5:
|
||||
perror(
|
||||
"iproute2mac: Ignoring last 2 arguments, not implemented: {} {}".format(
|
||||
argv[3], argv[4]
|
||||
)
|
||||
)
|
||||
|
||||
if argv[1] in ["via", "nexthop", "gw"]:
|
||||
gw = argv[2]
|
||||
elif argv[1] in ["dev"]:
|
||||
gw = "-interface " + argv[2]
|
||||
else:
|
||||
do_help_route()
|
||||
|
||||
prefix = argv[0]
|
||||
inet = "-inet6 " if ":" in prefix or af == 6 else ""
|
||||
|
||||
return execute_cmd(
|
||||
SUDO + " " + ROUTE + " add " + inet + prefix + " " + gw + " " + options
|
||||
)
|
||||
|
||||
|
||||
def do_route_del(argv, af):
|
||||
options = ""
|
||||
if argv[0] == "blackhole":
|
||||
argv.pop(0)
|
||||
if len(argv) != 1:
|
||||
return False
|
||||
if ":" in argv[0] or af == 6:
|
||||
options = " ::1 -blackhole"
|
||||
else:
|
||||
options = " 127.0.0.1 -blackhole"
|
||||
|
||||
prefix = argv[0]
|
||||
inet = "-inet6 " if ":" in prefix or af == 6 else ""
|
||||
return execute_cmd(
|
||||
SUDO + " " + ROUTE + " delete " + inet + prefix + options
|
||||
)
|
||||
|
||||
|
||||
def do_route_flush(argv, af):
|
||||
if not argv:
|
||||
perror('"ip route flush" requires arguments.')
|
||||
perror("")
|
||||
return False
|
||||
|
||||
# https://github.com/brona/iproute2mac/issues/38
|
||||
# http://linux-ip.net/html/tools-ip-route.html
|
||||
if argv[0] == "cache":
|
||||
print("iproute2mac: There is no route cache to flush in MacOS,")
|
||||
print(" returning 0 status code for compatibility.")
|
||||
return True
|
||||
elif len(argv) == 2 and argv[0] == "table" and argv[1] == "main":
|
||||
family = "-inet6" if af == 6 else "-inet"
|
||||
print("iproute2mac: Flushing all routes")
|
||||
return execute_cmd(SUDO + " " + ROUTE + " -n flush " + family)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def do_route_get(argv, af, json_print, pretty_json):
|
||||
target = argv[0]
|
||||
|
||||
inet = ""
|
||||
if ":" in target or af == 6:
|
||||
inet = "-inet6 "
|
||||
family = socket.AF_INET6
|
||||
else:
|
||||
family = socket.AF_INET
|
||||
|
||||
status, res = subprocess.getstatusoutput(
|
||||
ROUTE + " -n get " + inet + target
|
||||
)
|
||||
if status: # unix status or not in table
|
||||
perror(res)
|
||||
return False
|
||||
if res.find("not in table") >= 0:
|
||||
perror(res)
|
||||
exit(1)
|
||||
|
||||
res = dict(
|
||||
re.findall(
|
||||
r"^\W*((?:route to|destination|gateway|interface)): (.+)$",
|
||||
res,
|
||||
re.MULTILINE,
|
||||
)
|
||||
)
|
||||
|
||||
route = {"dst": res["route to"], "dev": res["interface"]}
|
||||
|
||||
if "gateway" in res:
|
||||
route["gateway"] = res["gateway"]
|
||||
|
||||
try:
|
||||
s = socket.socket(family, socket.SOCK_DGRAM)
|
||||
s.connect((route["dst"], 7))
|
||||
route["prefsrc"] = src_ip = s.getsockname()[0]
|
||||
s.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
route["flags"] = []
|
||||
route["uid"] = os.getuid()
|
||||
route["cache"] = []
|
||||
|
||||
if json_print:
|
||||
return json_dump([route], pretty_json)
|
||||
|
||||
print(
|
||||
route["dst"] +
|
||||
((" via " + route["gateway"]) if "gateway" in route else "") +
|
||||
" dev " + route["dev"] +
|
||||
((" src " + route["prefsrc"]) if "prefsrc" in route else "") +
|
||||
" uid " + str(route["uid"])
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# Addr Module
|
||||
@help_msg("do_help_addr")
|
||||
def do_addr(argv, af, json_print, pretty_json):
|
||||
if not argv:
|
||||
argv.append("show")
|
||||
|
||||
if any_startswith(["show", "lst", "list"], argv[0]):
|
||||
argv.pop(0)
|
||||
return do_addr_show(argv, af, json_print, pretty_json)
|
||||
elif "add".startswith(argv[0]) and len(argv) >= 3:
|
||||
argv.pop(0)
|
||||
return do_addr_add(argv, af)
|
||||
elif "delete".startswith(argv[0]) and len(argv) >= 3:
|
||||
argv.pop(0)
|
||||
return do_addr_del(argv, af)
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def do_addr_show(argv, af, json_print, pretty_json):
|
||||
return link_addr_show(argv, af, json_print, pretty_json, True)
|
||||
|
||||
|
||||
def do_addr_add(argv, af):
|
||||
if len(argv) < 2:
|
||||
return False
|
||||
|
||||
dst = ""
|
||||
if argv[1] == "peer":
|
||||
argv.pop(1)
|
||||
dst = argv.pop(1)
|
||||
|
||||
if argv[1] == "dev":
|
||||
argv.pop(1)
|
||||
else:
|
||||
return False
|
||||
try:
|
||||
addr = argv[0]
|
||||
dev = argv[1]
|
||||
except IndexError:
|
||||
perror("dev not found")
|
||||
exit(1)
|
||||
inet = ""
|
||||
if ":" in addr or af == 6:
|
||||
af = 6
|
||||
inet = " inet6"
|
||||
return execute_cmd(
|
||||
SUDO + " " + IFCONFIG + " " + dev + inet + " add " + addr + " " + dst
|
||||
)
|
||||
|
||||
|
||||
def do_addr_del(argv, af):
|
||||
if len(argv) < 2:
|
||||
return False
|
||||
if argv[1] == "dev":
|
||||
argv.pop(1)
|
||||
try:
|
||||
addr = argv[0]
|
||||
dev = argv[1]
|
||||
except IndexError:
|
||||
perror("dev not found")
|
||||
exit(1)
|
||||
inet = "inet"
|
||||
if ":" in addr or af == 6:
|
||||
af = 6
|
||||
inet = "inet6"
|
||||
return execute_cmd(
|
||||
SUDO + " " + IFCONFIG + " " + dev + " " + inet + " " + addr + " remove"
|
||||
)
|
||||
|
||||
|
||||
# Link module
|
||||
@help_msg("do_help_link")
|
||||
def do_link(argv, af, json_print, pretty_json):
|
||||
if not argv:
|
||||
argv.append("show")
|
||||
|
||||
if any_startswith(["show", "lst", "list"], argv[0]):
|
||||
argv.pop(0)
|
||||
return do_link_show(argv, af, json_print, pretty_json)
|
||||
elif "set".startswith(argv[0]):
|
||||
argv.pop(0)
|
||||
return do_link_set(argv, af)
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def do_link_show(argv, af, json_print, pretty_json):
|
||||
return link_addr_show(argv, af, json_print, pretty_json, False)
|
||||
|
||||
|
||||
def do_link_set(argv, af):
|
||||
if not argv:
|
||||
return False
|
||||
elif argv[0] == "dev":
|
||||
argv.pop(0)
|
||||
|
||||
if len(argv) < 2:
|
||||
return False
|
||||
|
||||
dev = argv[0]
|
||||
|
||||
IFCONFIG_DEV_CMD = SUDO + " " + IFCONFIG + " " + dev
|
||||
try:
|
||||
args = iter(argv)
|
||||
for arg in args:
|
||||
if arg == "up":
|
||||
if not execute_cmd(IFCONFIG_DEV_CMD + " up"):
|
||||
return False
|
||||
elif arg == "down":
|
||||
if not execute_cmd(IFCONFIG_DEV_CMD + " down"):
|
||||
return False
|
||||
elif arg in ["address", "addr", "lladdr"]:
|
||||
addr = next(args)
|
||||
if addr in ["random", "rand"]:
|
||||
addr = randomMAC()
|
||||
elif addr == "factory":
|
||||
(status, res) = subprocess.getstatusoutput(
|
||||
NETWORKSETUP + " -listallhardwareports"
|
||||
)
|
||||
if status != 0:
|
||||
return False
|
||||
details = re.findall(
|
||||
r"^(?:Device|Ethernet Address): (.+)$",
|
||||
res,
|
||||
re.MULTILINE,
|
||||
)
|
||||
addr = details[details.index(dev) + 1]
|
||||
if not execute_cmd(IFCONFIG_DEV_CMD + " lladdr " + addr):
|
||||
return False
|
||||
elif arg == "mtu":
|
||||
mtu = int(next(args))
|
||||
if not execute_cmd(IFCONFIG_DEV_CMD + " mtu " + str(mtu)):
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# Neigh module
|
||||
@help_msg("do_help_neigh")
|
||||
def do_neigh(argv, af, json_print, pretty_json):
|
||||
if not argv:
|
||||
argv.append("show")
|
||||
|
||||
if any_startswith(["show", "list", "lst"], argv[0]) and len(argv) <= 5:
|
||||
argv.pop(0)
|
||||
return do_neigh_show(argv, af, json_print, pretty_json)
|
||||
elif "flush".startswith(argv[0]):
|
||||
argv.pop(0)
|
||||
return do_neigh_flush(argv, af)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def do_neigh_show(argv, af, json_print, pretty_json):
|
||||
prefix = None
|
||||
dev = None
|
||||
try:
|
||||
while argv:
|
||||
arg = argv.pop(0)
|
||||
if arg == "to":
|
||||
prefix = argv.pop(0)
|
||||
elif arg == "dev":
|
||||
dev = argv.pop(0)
|
||||
elif prefix is None:
|
||||
prefix = arg
|
||||
else:
|
||||
return False
|
||||
if prefix:
|
||||
prefix = ipaddress.ip_network(prefix, strict=False)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
nd_ll_states = {
|
||||
"R": "REACHABLE",
|
||||
"S": "STALE",
|
||||
"D": "DELAY",
|
||||
"P": "PROBE",
|
||||
"I": "INCOMPLETE",
|
||||
"N": "INCOMPLETE",
|
||||
"W": "INCOMPLETE",
|
||||
}
|
||||
|
||||
neighs = []
|
||||
|
||||
if af != 4:
|
||||
res = subprocess.run(
|
||||
[NDP, "-an"], capture_output=True, text=True, check=True
|
||||
)
|
||||
for row in res.stdout.splitlines()[1:]:
|
||||
cols = row.split()
|
||||
entry = {"dst": re.sub(r"%.+$", "", cols[0])}
|
||||
if cols[1] != "(incomplete)":
|
||||
entry["lladdr"] = cols[1]
|
||||
entry["dev"] = cols[2]
|
||||
if dev and entry["dev"] != dev:
|
||||
continue
|
||||
if prefix and ipaddress.ip_address(entry["dst"]) not in prefix:
|
||||
continue
|
||||
if cols[1] == "(incomplete)" and cols[4] != "R":
|
||||
entry["status"] = ["INCOMPLETE"]
|
||||
else:
|
||||
entry["status"] = [nd_ll_states[cols[4]]]
|
||||
entry["router"] = len(cols) >= 6 and cols[5] == "R"
|
||||
neighs.append(entry)
|
||||
|
||||
if af != 6:
|
||||
args = [ARP, "-anl"]
|
||||
if dev:
|
||||
args += ["-i", dev]
|
||||
|
||||
res = subprocess.run(args, capture_output=True, text=True, check=True)
|
||||
for row in res.stdout.splitlines()[1:]:
|
||||
cols = row.split()
|
||||
entry = {"dst": cols[0]}
|
||||
if cols[1] != "(incomplete)":
|
||||
entry["lladdr"] = cols[1]
|
||||
entry["dev"] = cols[4]
|
||||
if dev and entry["dev"] != dev:
|
||||
continue
|
||||
if prefix and ipaddress.ip_address(entry["dst"]) not in prefix:
|
||||
continue
|
||||
if cols[1] == "(incomplete)":
|
||||
entry["status"] = ["INCOMPLETE"]
|
||||
else:
|
||||
entry["status"] = ["REACHABLE"]
|
||||
entry["router"] = False
|
||||
neighs.append(entry)
|
||||
|
||||
if json_print:
|
||||
return json_dump(neighs, pretty_json)
|
||||
|
||||
for nb in neighs:
|
||||
print(
|
||||
nb["dst"] +
|
||||
("", " dev " + nb["dev"], "")[dev == None] +
|
||||
("", " router")[nb["router"]] +
|
||||
" %s" % (nb["status"][0])
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def do_neigh_flush(argv, af):
|
||||
if len(argv) != 2:
|
||||
perror("Flush requires arguments.")
|
||||
exit(1)
|
||||
|
||||
if argv[0] != "dev":
|
||||
return False
|
||||
dev = argv[1]
|
||||
|
||||
if af != 4:
|
||||
print(
|
||||
"iproute2mac: NDP doesn't support filtering by interface,"
|
||||
"flushing all IPv6 entries."
|
||||
)
|
||||
execute_cmd(SUDO + " " + NDP + " -cn")
|
||||
if af != 6:
|
||||
execute_cmd(SUDO + " " + ARP + " -a -d -i " + dev)
|
||||
return True
|
||||
|
||||
|
||||
# Match iproute2 commands
|
||||
# https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/ip.c#n86
|
||||
cmds = [
|
||||
("address", do_addr),
|
||||
("route", do_route),
|
||||
("neighbor", do_neigh),
|
||||
("neighbour", do_neigh),
|
||||
("link", do_link),
|
||||
("help", do_help),
|
||||
]
|
||||
|
||||
|
||||
@help_msg("do_help")
|
||||
def main(argv):
|
||||
af = -1 # default / both
|
||||
json_print = False
|
||||
pretty_json = False
|
||||
|
||||
while argv and argv[0].startswith("-"):
|
||||
# Turn --opt into -opt
|
||||
argv[0] = argv[0][1:] if argv[0][1] == "-" else argv[0]
|
||||
# Process options
|
||||
if argv[0] == "-6":
|
||||
af = 6
|
||||
argv.pop(0)
|
||||
elif argv[0] == "-4":
|
||||
af = 4
|
||||
argv.pop(0)
|
||||
elif argv[0].startswith("-color"):
|
||||
perror("iproute2mac: Color option is not implemented")
|
||||
argv.pop(0)
|
||||
elif "-json".startswith(argv[0]):
|
||||
json_print = True
|
||||
argv.pop(0)
|
||||
elif "-pretty".startswith(argv[0]):
|
||||
pretty_json = True
|
||||
argv.pop(0)
|
||||
elif "-Version".startswith(argv[0]):
|
||||
print("iproute2mac, v" + VERSION)
|
||||
exit(0)
|
||||
elif "-help".startswith(argv[0]):
|
||||
return False
|
||||
else:
|
||||
perror('Option "{}" is unknown, try "ip help".'.format(argv[0]))
|
||||
exit(255)
|
||||
|
||||
if not argv:
|
||||
return False
|
||||
|
||||
for cmd, cmd_func in cmds:
|
||||
if cmd.startswith(argv[0]):
|
||||
argv.pop(0)
|
||||
# Functions return true or terminate with exit(255)
|
||||
# See help_msg and do_help*
|
||||
return cmd_func(argv, af, json_print, pretty_json)
|
||||
|
||||
perror('Object "{}" is unknown, try "ip help".'.format(argv[0]))
|
||||
exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
|
@ -3,4 +3,4 @@
|
|||
FOLDER=/Applications/OGAgent.app
|
||||
|
||||
cd $FOLDER
|
||||
python -m opengnsys.linux.OGAgentService $@
|
||||
/usr/local/bin/python3 -m opengnsys.linux.OGAgentService $@
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Directories
|
||||
SRCDIR=$(dirname "$0")
|
||||
BINDIR=/usr/bin
|
||||
INITDIR=/Library/LaunchDaemons
|
||||
BINDIR=/usr/local/bin
|
||||
LAUNCH_AGENTS_DIR=/Library/LaunchAgents
|
||||
LAUNCH_DAEMONS_DIR=/Library/LaunchDaemons
|
||||
|
||||
# Check if it needs to install Python dependencies:
|
||||
if ! which pip &>/dev/null; then
|
||||
easy_install pip
|
||||
pip install netifaces requests six
|
||||
fi
|
||||
|
||||
# Copying files.
|
||||
cp $SRCDIR/ogagent $BINDIR
|
||||
cp $SRCDIR/es.opengnsys.ogagent.plist $INITDIR
|
||||
|
||||
cp $SRCDIR/ip.py $BINDIR/ip ## override 'ip' from iproute2mac-1.4.2 with a more recent one
|
||||
cp $SRCDIR/es.opengnsys.agent.system.plist $LAUNCH_DAEMONS_DIR
|
||||
cp $SRCDIR/es.opengnsys.agent.user.plist $LAUNCH_AGENTS_DIR
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
ogausr_a = Analysis(
|
||||
['OGAgentUser.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[
|
||||
# ('cfg', 'cfg'), ## add the entire directory
|
||||
('img', 'img'), ## add the entire directory
|
||||
],
|
||||
hiddenimports=['win32timezone', 'socketserver', 'http.server', 'urllib'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
ogasvc_a = Analysis(
|
||||
['opengnsys\\windows\\OGAgentService.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=['win32timezone', 'socketserver', 'http.server', 'urllib'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
|
||||
MERGE(
|
||||
(ogausr_a, 'OGAgentUser', 'OGAgentUser'), ## class, py name, exe name
|
||||
(ogasvc_a, 'OGAgentService', 'OGAgentService')
|
||||
)
|
||||
|
||||
ogausr_pyz = PYZ(ogausr_a.pure)
|
||||
ogasvc_pyz = PYZ(ogasvc_a.pure)
|
||||
|
||||
ogausr_exe = EXE(
|
||||
ogausr_pyz,
|
||||
ogausr_a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='OGAgentUser',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['img\\oga.ico'],
|
||||
)
|
||||
ogasvc_exe = EXE(
|
||||
ogasvc_pyz,
|
||||
ogasvc_a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='OGAgentService',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['img\\oga.ico'],
|
||||
manifest='OGAgent.manifest',
|
||||
)
|
||||
|
||||
dist_name = 'OGAgent'
|
||||
coll = COLLECT(
|
||||
ogausr_exe,
|
||||
ogausr_a.binaries,
|
||||
ogausr_a.datas,
|
||||
|
||||
ogasvc_exe,
|
||||
ogasvc_a.binaries,
|
||||
ogasvc_a.datas,
|
||||
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name=dist_name,
|
||||
)
|
||||
|
||||
import shutil
|
||||
shutil.copytree ('cfg', '{}/{}/cfg'.format(DISTPATH, dist_name))
|
|
@ -34,6 +34,7 @@ import base64
|
|||
import json
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from about_dialog_ui import Ui_OGAAboutDialog
|
||||
|
@ -159,7 +160,8 @@ class OGASystemTray(QtWidgets.QSystemTrayIcon):
|
|||
|
||||
self.ipcport = int(cfg.get('ipc_port', IPC_PORT))
|
||||
|
||||
icon = QtGui.QIcon(':/images/img/oga.png')
|
||||
QtCore.QDir.addSearchPath('images', os.path.join(os.path.dirname(__file__), 'img'))
|
||||
icon = QtGui.QIcon('images:oga.png')
|
||||
|
||||
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
|
||||
self.menu = QtWidgets.QMenu(parent)
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.3.0
|
||||
1.3.3
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
# pylint: disable=unused-wildcard-import, wildcard-import
|
||||
|
||||
|
||||
from configparser import SafeConfigParser
|
||||
from configparser import ConfigParser
|
||||
|
||||
config = None
|
||||
|
||||
|
@ -45,7 +45,7 @@ def readConfig(client=False):
|
|||
|
||||
This is this way so we can protect ogagent.cfg against reading for non admin users on all platforms.
|
||||
"""
|
||||
cfg = SafeConfigParser()
|
||||
cfg = ConfigParser()
|
||||
if client is True:
|
||||
fname = 'ogclient.cfg'
|
||||
else:
|
||||
|
|
|
@ -57,7 +57,8 @@ class HTTPServerHandler(BaseHTTPRequestHandler):
|
|||
return
|
||||
|
||||
def sendJsonResponse(self, data):
|
||||
self.send_response(200)
|
||||
try: self.send_response(200)
|
||||
except Exception as e: logger.warn (str(e))
|
||||
data = json.dumps(data)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.send_header('Content-Length', str(len(data)))
|
||||
|
@ -117,7 +118,7 @@ class HTTPServerHandler(BaseHTTPRequestHandler):
|
|||
logger.error('HTTP ' + fmt % args)
|
||||
|
||||
def log_message(self, fmt, *args):
|
||||
logger.info('HTTP ' + fmt % args)
|
||||
logger.debug('HTTP ' + fmt % args)
|
||||
|
||||
|
||||
class HTTPThreadingServer(ThreadingMixIn, HTTPServer):
|
||||
|
@ -132,7 +133,9 @@ class HTTPServerThread(threading.Thread):
|
|||
|
||||
self.certFile = createSelfSignedCert()
|
||||
self.server = HTTPThreadingServer(address, HTTPServerHandler)
|
||||
self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True)
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
context.load_cert_chain(certfile=self.certFile)
|
||||
self.server.socket = context.wrap_socket(self.server.socket, server_side=True)
|
||||
|
||||
logger.debug('Initialized HTTPS Server thread on {}'.format(address))
|
||||
|
||||
|
|
|
@ -42,45 +42,69 @@ import subprocess
|
|||
import struct
|
||||
import array
|
||||
import six
|
||||
import json
|
||||
from opengnsys import utils
|
||||
import netifaces
|
||||
|
||||
ip_a_s = None
|
||||
|
||||
## make sure /usr/local/bin is in PATH
|
||||
## we need that to run /usr/local/bin/ip, which uses 'env' and pulls from PATH anyway
|
||||
def check_path():
|
||||
path = os.getenv ('PATH', '')
|
||||
usr_local_bin = '/usr/local/bin'
|
||||
|
||||
if usr_local_bin not in path.split (os.pathsep):
|
||||
os.environ['PATH'] = usr_local_bin + os.pathsep + path
|
||||
|
||||
def _getMacAddr(ifname):
|
||||
'''
|
||||
Returns the mac address of an interface
|
||||
Mac is returned as unicode utf-8 encoded
|
||||
'''
|
||||
if isinstance(ifname, list):
|
||||
return dict([(name, _getMacAddr(name)) for name in ifname])
|
||||
if isinstance(ifname, six.text_type):
|
||||
ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7)
|
||||
try:
|
||||
return netifaces.ifaddresses(ifname)[18][0]['addr']
|
||||
except Exception:
|
||||
return None
|
||||
for interface in ip_a_s:
|
||||
if interface.get ('ifname') != ifname: continue
|
||||
return interface.get ('address')
|
||||
return None
|
||||
|
||||
|
||||
def _getIpAddr(ifname):
|
||||
'''
|
||||
Returns the IP address of an interface
|
||||
Returns the first IP address of an interface
|
||||
IPv4 is preferred over IPv6
|
||||
IP is returned as unicode utf-8 encoded
|
||||
'''
|
||||
if isinstance(ifname, list):
|
||||
return dict([(name, _getIpAddr(name)) for name in ifname])
|
||||
if isinstance(ifname, six.text_type):
|
||||
ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7)
|
||||
try:
|
||||
return netifaces.ifaddresses(ifname)[2][0]['addr']
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
## loop and return the first IPv4 address found
|
||||
for interface in ip_a_s:
|
||||
if interface.get ('ifname') != ifname: continue
|
||||
for addr_info in interface.get ('addr_info', []):
|
||||
ip_address = addr_info.get ('local')
|
||||
try:
|
||||
ip_address.index ('.')
|
||||
return ip_address
|
||||
except: pass
|
||||
|
||||
## if nothing found, loop again and return the first IP found, which will be an IPv6
|
||||
for interface in ip_a_s:
|
||||
if interface.get ('ifname') != ifname: continue
|
||||
for addr_info in interface.get ('addr_info', []):
|
||||
return addr_info.get ('local')
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _getInterfaces():
|
||||
'''
|
||||
Returns a list of interfaces names
|
||||
'''
|
||||
return netifaces.interfaces()
|
||||
global ip_a_s
|
||||
|
||||
check_path()
|
||||
result = subprocess.run (['/usr/local/bin/ip', '-json', 'address', 'show'], capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0: raise Exception (f'Command "ip" failed with exit code {result.returncode}')
|
||||
ip_a_s = json.loads (result.stdout)
|
||||
return [i.get('ifname') for i in ip_a_s]
|
||||
|
||||
|
||||
def _getIpAndMac(ifname):
|
||||
|
@ -152,7 +176,7 @@ def logoff():
|
|||
import threading
|
||||
threading._DummyThread._Thread__stop = lambda x: 42
|
||||
|
||||
# Exec logout using AppleSctipt
|
||||
# Exec logout using AppleScript
|
||||
subprocess.call('/usr/bin/osascript -e \'tell app "System Events" to «event aevtrlgo»\'', shell=True)
|
||||
|
||||
|
||||
|
@ -244,7 +268,19 @@ def getSessionLanguage():
|
|||
'''
|
||||
Returns the user's session language
|
||||
'''
|
||||
return locale.getdefaultlocale()[0]
|
||||
lang = locale.getdefaultlocale()[0]
|
||||
if lang is None:
|
||||
return 'C'
|
||||
else:
|
||||
return lang
|
||||
|
||||
|
||||
def get_session_type():
|
||||
"""
|
||||
Minimal implementation of this required function
|
||||
:return: string
|
||||
"""
|
||||
return 'unknown'
|
||||
|
||||
|
||||
def showPopup(title, message):
|
||||
|
|
|
@ -65,7 +65,7 @@ def check_secret(fnc):
|
|||
else:
|
||||
raise Exception('Unauthorized operation')
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
logger.error(str(e))
|
||||
raise Exception(e)
|
||||
|
||||
return wrapper
|
||||
|
@ -83,7 +83,7 @@ def execution_level(level):
|
|||
else:
|
||||
raise Exception('Unauthorized operation')
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
logger.error(str(e))
|
||||
raise Exception(e)
|
||||
|
||||
return wrapper
|
||||
|
@ -149,6 +149,7 @@ class OpenGnSysWorker(ServerWorker):
|
|||
break
|
||||
# Raise error after timeout
|
||||
if not self.interface:
|
||||
## UnboundLocalError: cannot access local variable 'e' where it is not associated with a value
|
||||
raise e
|
||||
|
||||
# Loop to send initialization message
|
||||
|
@ -332,11 +333,23 @@ class OpenGnSysWorker(ServerWorker):
|
|||
:return: JSON object {"op": "launched"}
|
||||
"""
|
||||
logger.debug('Processing script request')
|
||||
# Decoding script (Windows scripts need a subprocess call per line)
|
||||
# Decoding script
|
||||
script = urllib.parse.unquote(base64.b64decode(post_params.get('script')).decode('utf-8'))
|
||||
logger.debug('received script {}'.format(script))
|
||||
if operations.os_type == 'Windows':
|
||||
script = 'import subprocess; {0}'.format(
|
||||
';'.join(['subprocess.check_output({0},shell=True)'.format(repr(c)) for c in script.split('\n')]))
|
||||
## for windows, we turn the script into utf16le, then to b64 again, and feed the blob to powershell
|
||||
u16 = script.encode ('utf-16le') ## utf16
|
||||
b64 = base64.b64encode (u16).decode ('utf-8') ## b64 (which returns bytes, so we need an additional decode(utf8))
|
||||
script = """
|
||||
import os
|
||||
import tempfile
|
||||
import subprocess
|
||||
cp = subprocess.run ("powershell -WindowStyle Hidden -EncodedCommand {}", capture_output=True)
|
||||
subprocs_log = os.path.join (tempfile.gettempdir(), 'opengnsys-subprocs.log')
|
||||
with open (subprocs_log, 'ab') as fd: ## TODO improve this logging
|
||||
fd.write (cp.stdout)
|
||||
fd.write (cp.stderr)
|
||||
""".format (b64)
|
||||
else:
|
||||
script = 'import subprocess; subprocess.check_output("""{0}""",shell=True)'.format(script)
|
||||
# Executing script.
|
||||
|
|
|
@ -61,7 +61,7 @@ def exceptionToMessage(e):
|
|||
if isinstance(arg, Exception):
|
||||
msg = msg + exceptionToMessage(arg)
|
||||
else:
|
||||
msg = msg + toUnicode(arg) + '. '
|
||||
msg = msg + str(arg) + '. '
|
||||
return msg
|
||||
|
||||
|
||||
|
|
|
@ -120,5 +120,9 @@ class OGAgentSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
win32serviceutil.HandleCommandLine(OGAgentSvc)
|
||||
if len(sys.argv) == 1:
|
||||
servicemanager.Initialize()
|
||||
servicemanager.PrepareToHostSingle(OGAgentSvc)
|
||||
servicemanager.StartServiceCtrlDispatcher()
|
||||
else:
|
||||
win32serviceutil.HandleCommandLine(OGAgentSvc)
|
||||
|
|
|
@ -43,11 +43,11 @@ OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in range(6))
|
|||
class LocalLogger(object):
|
||||
def __init__(self):
|
||||
# tempdir is different for "user application" and "service"
|
||||
# service wil get c:\windows\temp, while user will get c:\users\XXX\temp
|
||||
# service wil get c:\windows\temp, while user will get c:\users\XXX\appdata\local\temp
|
||||
logging.basicConfig(
|
||||
filename=os.path.join(tempfile.gettempdir(), 'opengnsys.log'),
|
||||
filemode='a',
|
||||
format='%(levelname)s %(asctime)s %(message)s',
|
||||
format='%(levelname)s %(asctime)s (%(threadName)s) %(message)s',
|
||||
level=logging.DEBUG
|
||||
)
|
||||
self.logger = logging.getLogger('opengnsys')
|
||||
|
@ -58,7 +58,7 @@ class LocalLogger(object):
|
|||
# our loglevels are 10000 (other), 20000 (debug), ....
|
||||
# logging levels are 10 (debug), 20 (info)
|
||||
# OTHER = logging.NOTSET
|
||||
self.logger.log(level / 1000 - 10, message)
|
||||
self.logger.log(int(level / 1000 - 10), message)
|
||||
|
||||
if level < INFO or self.serviceLogger is False: # Only information and above will be on event log
|
||||
return
|
||||
|
|
|
@ -64,7 +64,7 @@ def getNetworkInfo():
|
|||
ip: ip of the interface
|
||||
'''
|
||||
obj = win32com.client.Dispatch("WbemScripting.SWbemLocator")
|
||||
wmobj = obj.ConnectServer("localhost", "root\cimv2")
|
||||
wmobj = obj.ConnectServer("localhost", "root\\cimv2")
|
||||
adapters = wmobj.ExecQuery("Select * from Win32_NetworkAdapterConfiguration where IpEnabled=True")
|
||||
try:
|
||||
for obj in adapters:
|
||||
|
@ -102,12 +102,12 @@ def getWindowsVersion():
|
|||
'''
|
||||
Returns Windows version.
|
||||
'''
|
||||
import _winreg
|
||||
reg = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion')
|
||||
import winreg
|
||||
reg = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion')
|
||||
try:
|
||||
data = '{} {}'.format(_winreg.QueryValueEx(reg, 'ProductName')[0], _winreg.QueryValueEx(reg, 'ReleaseId')[0])
|
||||
data = '{} {}'.format(winreg.QueryValueEx(reg, 'ProductName')[0], winreg.QueryValueEx(reg, 'ReleaseId')[0])
|
||||
except Exception:
|
||||
data = '{} {}'.format(_winreg.QueryValueEx(reg, 'ProductName')[0], _winreg.QueryValueEx(reg, 'CurrentBuildNumber')[0])
|
||||
data = '{} {}'.format(winreg.QueryValueEx(reg, 'ProductName')[0], winreg.QueryValueEx(reg, 'CurrentBuildNumber')[0])
|
||||
reg.Close()
|
||||
return data
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
netifaces
|
||||
pywin32
|
||||
pyqt6
|
||||
requests
|
||||
urllib3
|
||||
six
|
||||
pycryptodome
|
||||
pyinstaller
|
||||
|
|
139
src/setup.py
139
src/setup.py
|
@ -1,139 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
@author: Ramón M. Gómez, ramongomez at us dot es
|
||||
"""
|
||||
|
||||
# ModuleFinder can't handle runtime changes to __path__, but win32com uses them
|
||||
try:
|
||||
# py2exe 0.6.4 introduced a replacement modulefinder.
|
||||
# This means we have to add package paths there, not to the built-in
|
||||
# one. If this new modulefinder gets integrated into Python, then
|
||||
# we might be able to revert this some day.
|
||||
# if this doesn't work, try import modulefinder
|
||||
try:
|
||||
import py2exe.mf as modulefinder
|
||||
except ImportError:
|
||||
import modulefinder
|
||||
import win32com
|
||||
import sys
|
||||
for p in win32com.__path__[1:]:
|
||||
modulefinder.AddPackagePath("win32com", p)
|
||||
for extra in ["win32com.shell"]: # ,"win32com.mapi"
|
||||
__import__(extra)
|
||||
m = sys.modules[extra]
|
||||
for p in m.__path__[1:]:
|
||||
modulefinder.AddPackagePath(extra, p)
|
||||
except ImportError:
|
||||
# no build path setup, no worries.
|
||||
pass
|
||||
|
||||
import os
|
||||
from distutils.core import setup
|
||||
import py2exe
|
||||
import sys
|
||||
|
||||
# update.sh changes this value
|
||||
VERSION='1.3.0'
|
||||
|
||||
sys.argv.append('py2exe')
|
||||
|
||||
|
||||
def get_requests_cert_file():
|
||||
"""Add Python requests or certifi .pem file for installers."""
|
||||
import requests
|
||||
f = os.path.join(os.path.dirname(requests.__file__), 'cacert.pem')
|
||||
if not os.path.exists(f):
|
||||
import certifi
|
||||
f = os.path.join(os.path.dirname(certifi.__file__), 'cacert.pem')
|
||||
return f
|
||||
|
||||
|
||||
class Target:
|
||||
|
||||
def __init__(self, **kw):
|
||||
self.__dict__.update(kw)
|
||||
# for the versioninfo resources
|
||||
self.version = VERSION
|
||||
self.name = 'OGAgentService'
|
||||
self.description = 'OpenGnsys Agent Service'
|
||||
self.author = 'Adolfo Gomez'
|
||||
self.url = 'https://opengnsys.es/'
|
||||
self.company_name = "OpenGnsys Project"
|
||||
self.copyright = "(c) 2014 VirtualCable S.L.U."
|
||||
self.name = "OpenGnsys Agent"
|
||||
|
||||
# Now you need to pass arguments to setup
|
||||
# windows is a list of scripts that have their own UI and
|
||||
# thus don't need to run in a console.
|
||||
|
||||
|
||||
ogaservice = Target(
|
||||
description='OpenGnsys Agent Service',
|
||||
modules=['opengnsys.windows.OGAgentService'],
|
||||
icon_resources=[(0, 'img\\oga.ico'), (1, 'img\\oga.ico')],
|
||||
cmdline_style='pywin32'
|
||||
)
|
||||
|
||||
# Some test_modules are hidden to py2exe by six, we ensure that they appear on "includes"
|
||||
HIDDEN_BY_SIX = ['SocketServer', 'SimpleHTTPServer', 'urllib']
|
||||
|
||||
setup(
|
||||
windows=[
|
||||
{
|
||||
'script': 'OGAgentUser-qt4.py',
|
||||
'icon_resources': [(0, 'img\\oga.ico'), (1, 'img\\oga.ico')]
|
||||
},
|
||||
],
|
||||
console=[
|
||||
{
|
||||
'script': 'OGAServiceHelper.py'
|
||||
}
|
||||
],
|
||||
service=[ogaservice],
|
||||
data_files=[('', [get_requests_cert_file()]), ('cfg', ['cfg/ogagent.cfg', 'cfg/ogclient.cfg'])],
|
||||
options={
|
||||
'py2exe': {
|
||||
'bundle_files': 3,
|
||||
'compressed': True,
|
||||
'optimize': 2,
|
||||
'includes': ['sip', 'PyQt4', 'win32com.shell', 'requests', 'encodings', 'encodings.utf_8'] + HIDDEN_BY_SIX,
|
||||
'excludes': ['doctest', 'unittest'],
|
||||
'dll_excludes': ['msvcp90.dll'],
|
||||
'dist_dir': '..\\bin',
|
||||
}
|
||||
},
|
||||
name='OpenGnsys Agent',
|
||||
version=VERSION,
|
||||
description='OpenGnsys Agent',
|
||||
author='Adolfo Gomez',
|
||||
author_email='agomez@virtualcable.es',
|
||||
zipfile='OGAgent.zip',
|
||||
)
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
import fileinput
|
||||
|
||||
def update_version():
|
||||
if os.path.isfile ('VERSION'):
|
||||
with open ('VERSION', 'r') as version_file:
|
||||
version = version_file.read().strip()
|
||||
|
||||
pattern = r'[0-9]*\.[0-9]*\.[0-9]*'
|
||||
matches = re.findall (pattern, version)
|
||||
win_version = matches[0]
|
||||
|
||||
with fileinput.FileInput ('about-dialog.ui', inplace=True) as file:
|
||||
for line in file:
|
||||
print (line.replace ('Version [^<]*', f'Version {version}'), end='')
|
||||
|
||||
with fileinput.FileInput ('opengnsys/__init__.py', inplace=True) as file:
|
||||
for line in file:
|
||||
print(line.replace ('VERSION=.*', f"VERSION='{version}'"), end='')
|
||||
|
||||
with open ('../windows/VERSION', 'w') as outfile:
|
||||
outfile.write (win_version + '\n')
|
||||
|
||||
else:
|
||||
print ('VERSION: No such file or directory')
|
||||
sys.exit (1)
|
||||
|
||||
def process_ui():
|
||||
subprocess.run (['pyuic6', 'about-dialog.ui', '-o', 'about_dialog_ui.py', '-x'])
|
||||
subprocess.run (['pyuic6', 'message-dialog.ui', '-o', 'message_dialog_ui.py', '-x'])
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.chdir (os.path.dirname (os.path.abspath (__file__)))
|
||||
update_version()
|
||||
process_ui()
|
|
@ -1,59 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# Copyright (c) 2024 Qindel Formación y Servicios S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
function update_version {
|
||||
if [[ -r VERSION ]]; then
|
||||
V="$(cat VERSION)"
|
||||
sed -i "s/Version [^<]*/Version $V/" about-dialog.ui
|
||||
sed -i "s/^VERSION='.*'$/VERSION='$V'/" setup.py
|
||||
sed -i "s/^VERSION='.*'$/VERSION='$V'/" opengnsys/__init__.py
|
||||
else
|
||||
echo 'src/VERSION: No such file or directory'
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function process_ui {
|
||||
pyuic6 about-dialog.ui -o about_dialog_ui.py -x
|
||||
pyuic6 message-dialog.ui -o message_dialog_ui.py -x
|
||||
}
|
||||
|
||||
function process_resources {
|
||||
## requires a virtualenv with pyside6
|
||||
## you can create it by doing 'mkvirtualenv -p python3 ogpyside6'
|
||||
## this will obviously go away in the future, but we need to merge the py3/qt6 change now
|
||||
~/.virtualenvs/ogpyside6/bin/pyside6-rcc -o OGAgent_rc.py OGAgent.qrc
|
||||
sed -i -e '/^from PySide6 import QtCore/s/PySide6/PyQt6/' OGAgent_rc.py
|
||||
}
|
||||
|
||||
cd $(dirname "$0")
|
||||
update_version
|
||||
process_ui
|
||||
process_resources
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
cd "$(dirname "$0")"
|
||||
export WINEARCH=win32
|
||||
export WINEPREFIX=$PWD/wine
|
||||
grep -o "[0-9]*\.[0-9]*\.[0-9]*" ../src/VERSION > VERSION
|
||||
wine cmd /c c:\\ogagent\\build.bat
|
||||
chmod -x ../OGAgentSetup*.exe
|
|
@ -1,7 +0,0 @@
|
|||
C:
|
||||
CD \ogagent\src
|
||||
python setup.py
|
||||
CD ..
|
||||
RENAME bin\OGAgentUser-qt4.exe OGAgentUser.exe
|
||||
"C:\Program Files\NSIS\makensis.exe" ogagent.nsi
|
||||
|
|
@ -88,8 +88,8 @@ Section -Main SEC0000
|
|||
SetShellVarContext all
|
||||
SetOutPath $INSTDIR
|
||||
SetOverwrite on
|
||||
File /r bin\*.*
|
||||
File vcredist_x86.exe
|
||||
File /r src\dist\OGAgent\*.*
|
||||
File windows\VC_redist.x64.exe
|
||||
File src\VERSION
|
||||
WriteRegStr HKLM "${REGKEY}\Components" Main 1
|
||||
SectionEnd
|
||||
|
@ -111,7 +111,7 @@ Section -post SEC0001
|
|||
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" OGAgentTool $INSTDIR\OGAgentUser.exe
|
||||
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1
|
||||
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1
|
||||
ExecWait '"$INSTDIR\vcredist_x86.exe" /passive /norestart'
|
||||
ExecWait '"$INSTDIR\VC_redist.x64.exe" /passive /norestart'
|
||||
# Add the application to the firewall exception list - All Networks - All IP Version - Enabled
|
||||
# SimpleFC::AddApplication "OpenGnsys Agent Service" "$INSTDIR\OGAgentService.exe" 0 2 "" 1
|
||||
# SimpleFC::AdvAddRule [name] [description] [protocol] [direction]
|
||||
|
@ -128,8 +128,6 @@ Section -post SEC0001
|
|||
WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Power" HiberbootEnabled 0
|
||||
# Install service
|
||||
nsExec::Exec /OEM "$INSTDIR\OGAgentService.exe --startup auto install" # Add service after installation
|
||||
# Update recovery options
|
||||
nsExec::Exec /OEM "$INSTDIR\OGAServiceHelper.exe"
|
||||
Exec "net start ogagent"
|
||||
Exec "$INSTDIR\OGAgentUser.exe"
|
||||
SectionEnd
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# We need:
|
||||
# * Wine (32 bit)
|
||||
# * winetricks (in some distributions)
|
||||
|
||||
export WINEARCH=win32 WINEPREFIX=$PWD/wine WINEDEBUG=fixme-all
|
||||
WINE=wine
|
||||
|
||||
download() {
|
||||
mkdir downloads
|
||||
# Get needed software
|
||||
cd downloads
|
||||
wget -nd https://www.python.org/ftp/python/2.7.17/python-2.7.17.msi -O python-2.7.msi
|
||||
wget -nd https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi
|
||||
wget -nd https://bootstrap.pypa.io/get-pip.py
|
||||
wget -nd https://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.4/PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe/download -O pyqt-install.exe
|
||||
wget -nd https://prdownloads.sourceforge.net/nsis/nsis-3.05-setup.exe?download -O nsis-install.exe
|
||||
wget -nd http://nsis.sourceforge.net/mediawiki/images/d/d7/NSIS_Simple_Firewall_Plugin_1.20.zip
|
||||
cd ..
|
||||
}
|
||||
|
||||
install_python() {
|
||||
if which winetricks &>/dev/null; then
|
||||
echo "Setting up wine prefix (using winetricks)"
|
||||
winetricks
|
||||
fi
|
||||
|
||||
cd downloads
|
||||
echo "Installing python"
|
||||
$WINE msiexec /qn /i python-2.7.msi
|
||||
echo "Installing vc for python"
|
||||
$WINE msiexec /qn /i VCForPython27.msi
|
||||
|
||||
echo "Installing pyqt (needs X)"
|
||||
$WINE pyqt-install.exe
|
||||
echo "Installing nsis (needs X?)"
|
||||
$WINE nsis-install.exe
|
||||
|
||||
cd ..
|
||||
}
|
||||
|
||||
setup_pip() {
|
||||
echo "Seting up pip..."
|
||||
$WINE C:\\Python27\\python -m pip install --upgrade pip
|
||||
}
|
||||
|
||||
install_packages() {
|
||||
echo "Installing pywin32"
|
||||
$WINE C:\\Python27\\python -m pip install pywin32
|
||||
echo "Installing py2exe"
|
||||
$WINE C:\\Python27\\python -m pip install py2exe_py2
|
||||
echo "Installing required packages"
|
||||
$WINE C:\\Python27\\python -m pip install requests six
|
||||
# Using easy_install instead of pip to install pycrypto
|
||||
$WINE C:\\Python27\\Scripts\\easy_install http://www.voidspace.org.uk/python/pycrypto-2.6.1/pycrypto-2.6.1.win32-py2.7.exe
|
||||
# Copy nsis required NSIS_Simple_Firewall_Plugin_1
|
||||
echo "Copying simple firewall plugin for nsis installer"
|
||||
unzip -o downloads/NSIS_Simple_Firewall_Plugin_1.20.zip SimpleFC.dll -d $WINEPREFIX/drive_c/Program\ Files/NSIS/Plugins/x86-ansi/
|
||||
unzip -o downloads/NSIS_Simple_Firewall_Plugin_1.20.zip SimpleFC.dll -d $WINEPREFIX/drive_c/Program\ Files/NSIS/Plugins/x86-unicode/
|
||||
}
|
||||
|
||||
download
|
||||
install_python
|
||||
setup_pip
|
||||
install_packages
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
C:
|
||||
cd \Users\Docker\Downloads
|
||||
mkdir setup
|
||||
|
||||
rem creamos directorio setup, nos bajamos cosas y mas tarde lo borramos
|
||||
rem pero el VC_redist hace falta para el empaquetado, asi que lo descargamos fuera de setup para no borrarlo
|
||||
|
||||
curl https://www.python.org/ftp/python/3.12.3/amd64/core.msi --output setup\core.msi
|
||||
curl https://www.python.org/ftp/python/3.12.3/amd64/dev.msi --output setup\dev.msi
|
||||
curl https://www.python.org/ftp/python/3.12.3/amd64/exe.msi --output setup\exe.msi
|
||||
curl https://www.python.org/ftp/python/3.12.3/amd64/lib.msi --output setup\lib.msi
|
||||
curl https://www.python.org/ftp/python/3.12.3/amd64/path.msi --output setup\path.msi
|
||||
curl https://www.python.org/ftp/python/3.12.3/amd64/pip.msi --output setup\pip.msi
|
||||
curl https://aka.ms/vs/17/release/vc_redist.x64.exe --location --output VC_redist.x64.exe
|
||||
curl https://prdownloads.sourceforge.net/nsis/nsis-3.05-setup.exe?download --location --output setup\nsis-install.exe
|
||||
curl http://nsis.sourceforge.net/mediawiki/images/d/d7/NSIS_Simple_Firewall_Plugin_1.20.zip --location --output setup\NSIS_Simple_Firewall_Plugin_1.20.zip
|
||||
|
||||
cd setup
|
||||
msiexec /i core.msi TARGETDIR=C:\Python312
|
||||
msiexec /i dev.msi TARGETDIR=C:\Python312
|
||||
msiexec /i exe.msi TARGETDIR=C:\Python312
|
||||
msiexec /i lib.msi TARGETDIR=C:\Python312
|
||||
msiexec /i path.msi TARGETDIR=C:\Python312
|
||||
msiexec /i pip.msi TARGETDIR=C:\Python312
|
||||
cd ..
|
||||
VC_redist.x64.exe /install /quiet /passive /norestart
|
||||
|
||||
ftype PythonScript=C:\Python312\python.exe "%1" %*
|
||||
assoc .py=PythonScript
|
||||
PATH=C:\Python312;C:\Python312\Scripts;%PATH%
|
||||
setx PATH "C:\Python312;C:\Python312\Scripts;%PATH%"
|
||||
|
||||
python -m pip install --upgrade wheel pip
|
||||
pip install -r F:\src\requirements.txt
|
||||
|
||||
setup\nsis-install.exe /S
|
||||
|
||||
powershell -command "Expand-Archive setup\NSIS_Simple_Firewall_Plugin_1.20.zip nsis-fp"
|
||||
copy nsis-fp\SimpleFC.dll "C:\Program Files (x86)\NSIS\Plugins\x86-ansi\"
|
||||
copy nsis-fp\SimpleFC.dll "C:\Program Files (x86)\NSIS\Plugins\x86-unicode\"
|
||||
rmdir nsis-fp /s /q
|
||||
|
||||
rmdir setup /s /q
|
Loading…
Reference in New Issue