Some checks failed
Deployment Verification / deploy-and-test (push) Failing after 29s
312 lines
9.3 KiB
Python
312 lines
9.3 KiB
Python
import requests
|
|
import yaml
|
|
import json
|
|
import os
|
|
import io
|
|
import base64
|
|
from PIL import Image
|
|
#import tkinter
|
|
#import _tkinter
|
|
#tkinter._test()
|
|
|
|
|
|
#sudo apt-get install python-imaging-tk
|
|
#sudo apt-get install python3-tk
|
|
|
|
# USAGE:
|
|
# 1. Find the item here:
|
|
# https://apphub.swimlane.com/swimbundles/swimlane/sw_alienvault_threatcrowd
|
|
# 2.
|
|
# https://jsonlint.com/
|
|
|
|
# META: data["meta"]. Stuff like count. May be useful :)
|
|
|
|
def parse_data(data):
|
|
openapi = {
|
|
"openapi": "3.0.2",
|
|
"info": {
|
|
"title": "",
|
|
"description": "",
|
|
"version": "1.0.0",
|
|
"contact": {
|
|
"name": "@frikkylikeme",
|
|
"url": "https://twitter.com/frikkylikeme",
|
|
"email": "frikky@shuffler.io"
|
|
}
|
|
},
|
|
"paths": {},
|
|
"components": {
|
|
"schemas": {},
|
|
"securitySchemes": {},
|
|
}
|
|
}
|
|
|
|
data = data["swimbundle"]
|
|
filename = "%s.yaml" % data["product"].replace(" ", "_").lower()
|
|
openapi["info"]["title"] = "%s %s" % (data["vendor"], data["product"])
|
|
openapi["info"]["description"] = "Automated generation of %s" % (openapi["info"]["title"])
|
|
# data["description"]
|
|
|
|
# https://swagger.io/docs/specification/authentication/
|
|
try:
|
|
asset = data["asset"]
|
|
inputparams = asset["inputParameters"]
|
|
|
|
try:
|
|
openapi["servers"] = [inputparams["api_url"]["example"]]
|
|
except KeyError as e:
|
|
#print(inputparams)
|
|
#print("Field error: %s" % e)
|
|
pass
|
|
|
|
authset = False
|
|
try:
|
|
tmpauth = inputparams["api_user"]
|
|
tmpauth = inputparams["api_key"]
|
|
|
|
openapi["components"]["securitySchemes"] = {
|
|
"BasicAuth": {
|
|
"type": "http",
|
|
"scheme": "basic"
|
|
}
|
|
}
|
|
authset = True
|
|
except KeyError as e:
|
|
pass
|
|
|
|
try:
|
|
tmpauth = inputparams["username"]
|
|
tmpauth = inputparams["password"]
|
|
|
|
openapi["components"]["securitySchemes"] = {
|
|
"BasicAuth": {
|
|
"type": "http",
|
|
"scheme": "basic"
|
|
}
|
|
}
|
|
authset = True
|
|
except KeyError as e:
|
|
pass
|
|
|
|
#if not authset:
|
|
# print("AUTH NOT SET: %s" % inputparams)
|
|
|
|
except KeyError as e:
|
|
print("KeyError asset: %s" % e)
|
|
|
|
cnt = 0
|
|
paramnames = []
|
|
for task in data["tasks"]:
|
|
method = "post"
|
|
|
|
openapi["paths"]["tmp%d" % cnt] = {}
|
|
openapi["paths"]["tmp%d" % cnt][method] = {
|
|
"summary": task["name"],
|
|
"description": task["description"],
|
|
"parameters": [],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Successful request",
|
|
|
|
}
|
|
},
|
|
}
|
|
|
|
taskcategory = task["family"]
|
|
taskname = task["name"]
|
|
paramnames.append(taskname)
|
|
|
|
for key, value in task["inputParameters"].items():
|
|
schema = "string"
|
|
inVar = "query"
|
|
|
|
if value["type"] == 6:
|
|
inVar = "body"
|
|
|
|
schema = "string"
|
|
schemaset = False
|
|
if value["type"] != 1:
|
|
if (value["type"] == 7):
|
|
schema = "boolean"
|
|
schemaset = True
|
|
|
|
if schema == "string" and schemaset:
|
|
print("Should change type: %d" % value["type"])
|
|
print(task["name"])
|
|
print(value["name"])
|
|
|
|
example = ""
|
|
try:
|
|
example = value["example"]
|
|
except KeyError:
|
|
pass
|
|
|
|
description = ""
|
|
try:
|
|
description = value["description"]
|
|
except KeyError:
|
|
pass
|
|
|
|
required = False
|
|
try:
|
|
required = value["required"]
|
|
except KeyError:
|
|
pass
|
|
|
|
openapi["paths"]["tmp%d" % cnt][method]["parameters"].append({
|
|
"name": value["name"],
|
|
"required": required,
|
|
"example": example,
|
|
"description": description,
|
|
"schema": {"type": schema},
|
|
"in": inVar
|
|
})
|
|
|
|
if len(task["availableOutputVariables"]) > 0:
|
|
openapi["paths"]["tmp%d" % cnt][method]["responses"]["200"]["content"] = {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/tmp%d" % cnt
|
|
}
|
|
}
|
|
}
|
|
|
|
#responses:
|
|
# '200':
|
|
# content:
|
|
# application/json:
|
|
# schema:
|
|
# $ref: '#/components/schemas/tmp1'
|
|
#description: Successful request
|
|
|
|
openapi["components"]["schemas"]["tmp%d" % cnt] = {
|
|
"type": "object",
|
|
"properties": {},
|
|
}
|
|
|
|
for key, value in task["availableOutputVariables"].items():
|
|
if key == "response_code":
|
|
continue
|
|
|
|
openapi["components"]["schemas"]["tmp%d" % cnt]["properties"][key] = {
|
|
"type": "string"
|
|
}
|
|
|
|
cnt += 1
|
|
|
|
print("%s: %d" % (openapi["info"]["title"], len(paramnames)))
|
|
|
|
return filename, openapi
|
|
|
|
def dump_data(filename, openapi, category):
|
|
generatedfile = "generated/%s/%s" % (category, filename)
|
|
try:
|
|
with open(generatedfile, "w+") as tmp:
|
|
tmp.write(yaml.dump(openapi))
|
|
except FileNotFoundError:
|
|
try:
|
|
os.mkdir("generated/%s" % category)
|
|
with open(generatedfile, "w+") as tmp:
|
|
tmp.write(yaml.dump(openapi))
|
|
|
|
except FileExistsError:
|
|
pass
|
|
|
|
if __name__ == "__main__":
|
|
#https://apphub.swimlane.com/
|
|
categories = [
|
|
"Investigation",
|
|
"Endpoint Security & Management",
|
|
"Network Security & Management",
|
|
"Communication",
|
|
"SIEM & Log Management",
|
|
"Governance & Risk Management",
|
|
"Vulnerability & Patch Management",
|
|
"Ticket Management",
|
|
"DevOps & Application Security",
|
|
"Identity & Access Management",
|
|
"Infrastructure",
|
|
"Miscellaneous",
|
|
]
|
|
|
|
search_category = categories[2]
|
|
total = 0
|
|
for search_category in categories:
|
|
number = 1
|
|
innertotal = 0
|
|
|
|
while(True):
|
|
url = "https://apphub.swimlane.io/api/search/swimbundles?page=%d" % number
|
|
|
|
json = {"fields": {"family": search_category}}
|
|
ret = requests.post(
|
|
url,
|
|
json=json,
|
|
)
|
|
|
|
if ret.status_code != 201:
|
|
print("RET NOT 201: %d" % ret.status_code)
|
|
break
|
|
|
|
parsed = ret.json()
|
|
try:
|
|
category = parsed["data"][0]["swimbundleMeta"]["family"][0]
|
|
except KeyError:
|
|
category = ""
|
|
except IndexError:
|
|
category = ""
|
|
|
|
if category == "":
|
|
break
|
|
|
|
for data in parsed["data"]:
|
|
try:
|
|
filename, openapi = parse_data(data)
|
|
except:
|
|
try:
|
|
print("Skipping %s %s because of an error" % (data["vendor"], data["product"]))
|
|
except KeyError:
|
|
pass
|
|
|
|
continue
|
|
|
|
openapi["tags"] = [
|
|
{
|
|
"name": category,
|
|
}
|
|
]
|
|
|
|
appid = data["swimbundleMeta"]["logo"]["id"]
|
|
logoUrl = "https://apphub.swimlane.io/api/logos/%s" % appid
|
|
logodata = requests.get(logoUrl)
|
|
if logodata.status_code == 200:
|
|
logojson = logodata.json()
|
|
try:
|
|
logobase64 = logojson["data"]["base64"]
|
|
#.split(",")[1]
|
|
|
|
openapi["info"]["x-logo"] = logobase64
|
|
#print(logobase64)
|
|
#msg = base64.b64decode(logobase64)
|
|
#with io.BytesIO(msg) as buf:
|
|
# with Image.open(buf) as tempImg:
|
|
# newWidth = 174 / tempImg.width # change this to what ever width you need.
|
|
# newHeight = 174 / tempImg.height # change this to what ever height you need.
|
|
# newSize = (int(newWidth * tempImg.width), int(newHeight * tempImg.height))
|
|
# newImg1 = tempImg.resize(newSize)
|
|
# lbl1.IMG = ImageTk.PhotoImage(image=newImg1)
|
|
# lbl1.configure(image=lbl1.IMG)
|
|
except KeyError:
|
|
print("Failed logo parsing for %s" % appid)
|
|
pass
|
|
|
|
dump_data(filename, openapi, category)
|
|
innertotal += 1
|
|
total += 1
|
|
|
|
number += 1
|
|
|
|
print("Created %d openapi specs from Swimlane with category %s" % (innertotal, search_category))
|
|
|
|
print("\nCreated %d TOTAL openapi specs from Swimlane" % (total))
|