Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Provides utilities and integration code which may be useful when developing various drivers for use within the Apitax framework.
Pronounced: ahhp-ehh-tax
tl;dr: Code examples are at the very bottom of this documentation; however, I highly suggest you read through the documentation to learn what is possible.
Finally, as Apitax features an exponential amount of various interactions, not all of them are documented here. Experiment with the syntax, Learn from the syntax, and Enjoy Apitax!
Apitax is an API automation framework utilizing Commandtax and Scriptax. Commandtax is an API language which helps to quickly prototype powerful rest API requests. Scriptax is an automation language which utilizes Commandtax.
A more winded (and more detailed!) description called Why use Apitax is at the very bottom of this documentation.
I highly recommend you use the starter pack to get Apitax up and running. It provides you with a templated repository of files which you can change to better suit your application.
The Apitax StarterPack can be found here: https://github.com/Apitax/StarterPack
StarterPack Benefits and Features:
Apitax on PyPi: https://pypi.org/project/apitax/
Using pip, you can bring in Apitax to your project.
Docker is the recommended way to deploy Apitax. Please see the StarterPack for examples on how this can be achieved. While building Apitax yourself is possible, it is only recommended to do so if you are developing Apitax.
Warning: Apitax/Core is a base Apitax image. It is not meant to be deployed by itself, and must be used as a base for an application image which uses Apitax. Please see the StarterPack for more details.
For the programmers out there: Think of the Apitax image as an abstract class
in a programming language, and it is up to you to build the class that inheirits Apitax.
You can use the provided Docker file to quickly build an Apitax image. However, this image will not function correctly as it will be missing config.txt
, project.py
, and will have no drivers. Please see the StarterPack for more details on how this should all be included.
Steps:
docker build --no-cache -t my-amazing-image .
docker run -d -p 5080:5080 my-amazing-image
-d
flag.python setup.py sdist bdist_wheel
twine upload dist/* -r pypi
pandoc
if it is not already installed: sudo apt-get install pandoc
pandoc -o readme.docx -f markdown -t docx README.md
This is sometimes necessary due to a bug in the antlr compiler with regards to paths
#!/bin/bash
grammardir=~/grammar
apitaxdir=~/apitax-dev/Apitax/apitax/grammar
antlr='antlr-4.7.1-complete.jar'
java -jar $grammardir/$antlr -Dlanguage=Python3 $grammardir/src/$2
java -jar $grammardir/$antlr -lib $grammardir/src -o $grammardir/build -listener -visitor -Dlanguage=Python3 $grammardir/src/$1
cp -r $grammardir/build/* $apitaxdir/build
cp $grammardir/src/$2 $apitaxdir/src
cp $grammardir/src/$1 $apitaxdir/src
bash ~/grammar/run.sh Ah210.g4 AhLex210.g4
Commandtax is an efficient and fluent command language for Rest API's. Think of it as a better curl supporting better logging, better debugging, and more sensible flags.
Scriptax is an API first automation language. Scriptax is not a general purpose language, instead it exists as a language tailored to optimizing automation in an API based environment.
ct(required: "\<someCommand\>") {% %}
get(required: "\<someCommand\>", optional: {dataObj}, optional: param1...n) {% %}
post, query, path, header
put(required: "\<someCommand\>", optional: {dataObj}, optional: param1...n) {% %}
post, query, path, header
patch(required: "\<someCommand\>", optional: {dataObj}, optional: param1...n) {% %}
post, query, path, header
post(required: "\<someCommand\>", optional: {dataObj}, optional: param1...n) {% %}
post, query, path, header
delete(required: "\<someCommand\>", optional: {dataObj}, optional: param1...n) {% %}
post, query, path, header
new OpenstackNetworks(optional=parameters);
\<attributes\> \<methodName\>(optional=parameters) {}
api
or script
\<methodName\>(optional=parameters);
async
api async getNetworks() { }
async get("http://placeholderjson.com/users", {}) {% %}
someVar = async get("http://placeholderjson.com/users", {}) {% %}
await \<someOptionalVar\>;
result = await openstack.getNetworks();
results
variablestr()
int()
dec()
bool()
list()
dict()
\#
\$
\!
\@
extends(\<someScriptPath\>);
del(\<someVar\>)
return \<optionalVar\>
options(optional=parameters)
sig(param1Required, thisParam=isOptional, thisOneisRequired);
if (condition) {}
while (condition) {}
for \<someVar\> in \<existingVar\> {}
for \<someVar\> in \<someNumber\> {}
each \<someList\> {% %};
results
to the current item and executing instructions in an isolated callback\<someVar\> = \<someExpression\>
"this is a string {{ someVar }}"
\< someExpression \>
from driverName import someScript as someName
from
and as
are optionalauth(\<someAuthObject\>)
login(username={{someUser}}, password={{somePass}}, token={{someToken}}, driver={{someDriver}}, extra={{someJSONObj}})
auth
such as: auth login(username=test, password=test123);
endpoint(someEndpointName@someDriver)
getCatalog
method, this will return the the endpoint found in the catalog of the specified driverurl
such as: url endpoint('keystone@openstack')
url(\<someUrl\>)
log("log some output to the console & log file")
// some comment
/* some comment spanning multiple lines */
In Scriptax, there is no global scope. Every piece of data belongs to a scope. There are many different scope types within Scriptax:
result
variable will be accessible as well as any other values passed in via (optional=parameter) -> {% %}
syntax. Typically callback scope is read only and any changes made to any variables in here will only be changed within the callback scope. The only exception to this is the result
variable which is generally used to pass data back in a return style.Script
, Method
, and Flow/Block
scopes will all inherit their parent scopes. Callback
scopes on the other hand are completely isolated and must be told explicilty which symbols are allowed in and they will only be allowed in as read-only.
class
in other programming and scripting languages.static
. In other words, methods are not unique per instance and can be called on the script itself or on a script instance. If a method is called via the script itself and attempts to utilize script scope variables, an error will be thrown.Scriptax has a structure which must be followed or else errors will be thrown or the script will complete with errors.
The first few lines of a script are dedicated to global_statements
. These statements include extends
, signature
, options
, and finally imports
. Scriptax is extremely strict when it comes to global_statements
and thus they must even be in order. If you choose to use extends
it must be the first statement in the file with no exceptions. If you choose to use signature
it must come immediatly after extends
, but if you aren't using extends
then signature
must be the first statement within the file, so on and so forth. The order of global_statements
is as follows:
extends
signature
options
imports
While extends
, signature
, and options
should only ever occur 0 or 1 times within a script file, imports
can occur 0..n times within a file.
After the global_statements
feel free to use any non global statements as you see fit.
sig
should be done like so: param.firstParam
where firstParam
is the name of the parametersig
line if nessecary.await;
to ensure all async requests are completed before it returns to the parent script.
await;
followed by return \<someVar\>;
is also acceptabledel \<someVar\>
** This has been redone and requires updated configuration **
project.py
file. Please see Apitax/StarterPack for an example of how this can be done.custom --get --url <someEndpoint>
custom --get --url <someEndpoint> --data-param '{"is_domain": true}'
custom --post --url <someEndpoint> --data-post '{"title": "im the title"}'
custom --put --url <someEndpoint>
custom --patch --url <someEndpoint>
custom --delete --url <someEndpoint>
custom --get --url <someEndpoint> --data-param '{"user.id": "1"}'
custom --get --url <someEndpoint>/with/some/{ohyear}/url/params/{981} --data-param '{"is_domain": true}' --data-path '{"ohyeah":"no", "981": "yes"}'
script ~/path/to/my/script.ah
// async-tests.ah
url "https://jsonplaceholder.typicode.com";
bob = [];
threads = [];
/*each get("/users", {})
{%
url "https://jsonplaceholder.typicode.com";
threads[] = async get("/posts", {
"query": {
"userId": result.id,
},
}) {%
log("The user has these posts: " + result);
%};
%};*/
for user in get("/users", {})
threads[] = async get("/posts", {
"query": {
"userId": user.id,
},
}) {%
log("The user has these posts: " + result);
//bob[] = result;
%};
await threads;
del threads;
script("apitax/grammar/scripts/base.ah");
log("yo man im at the end");
/*for user in get("/users", {})
threads = async get("/posts", {
"query": {
"userId": user.id,
},
}) {%
log("The user has these posts: " + result);
bob[] = result
%};
//bob[] = "hey";
for t in threads
await t;
log(bob);
log("Im quite confused");*/
// base.ah
url "https://jsonplaceholder.typicode.com";
for user in get("/users")
{
/*result = get("/posts", {
"query": {
"userId": user.id,
}
});
log("The user has these posts: " + result);*/
log("the user has ID: " + user.id);
async get("/posts", {
"query": {
"userId": user.id,
}
}) {%
log("The user has these posts: " + result);
%};
}
response = post("/posts", {
"post": {
"title":'foo',
"body":'bar',
"userId":1
}
});
log(script("apitax/grammar/scripts/jen.ah", {}, "i am parameter 1", "i am parameter 2"));
//response = ;
log("Please " + ct("tests my script", {}, "i should be a parameter"));
testlist = ["one", "two", 'three', ["a", 'b', 'c', 'd'], {"test": "failed", "yes": "no"}];
log(#testlist.0);
/*async ct("some command execution")
{
log("some integrated callback");
}
async ct("some command execution");
status = async ct("some command execution");
await status;
status = [firstAsync, secondAsync];
await status;
async bobo in get("/users")
{
log("Async callback: " + bobo);
}*/
async get("/users");
somelabel = async get("/users")
{%
log("I am an optional callback");
%};
//anotherRequest0 = async get("/users");
//anotherRequest1 = async get("/users");
//anotherRequest2 = async get("/users");
await somelabel;
log("i am that label" + somelabel);
get("/users") {%
log(result);
%};
async get("/users") {%
log(result);
%};
for iter in 10 {
async get("/posts", {
"query": {
"userId": iter,
}
}) {%
log("The user has these posts: " + result);
%};
}
log("here is where the magic happens");
get("/posts", {
"query": {
"userId": 5,
}
}) {%
log("The user has these posts: " + result);
%};
await;
// jen.ah
options dict('{"params": ["name", "game"]}');
answer=2+2;
name "quinn";
set qwer = "im in jens script";
export qwer;
//export ct("script apitax/grammar/scripts/shawn.ah");
set iam.hope.this.works = ct("custom --get --url https://jsonplaceholder.typicode.com/users");
export iam;
set test = "hello";
//return '{"cool": "beans"}';
log(params.passed.0);
log(params.passed.1);
log(params.name);
log(params.game);
log(2+2);
return params.passed.1;
//return "test";
await;
// my_script.ah
options dict('{"params": ["first"]}');
log("I got here");
log(params.first);
return "work";
await;
Let's presume that a backend exists only as an entity that does nothing until it is told to do something.
If this is the case let's also assume there will be no interface into the backend other than a RESTful API.
Okay, so let's say we want to build a frontend that will list every user's 10 most recent posts.
One way we can do this is to make an API request to retrieve a list of our users. Then, in JavaScript, we can loop through that list of users, and for each one we can make an API request to get their most recent posts. In Javascript, we can then compile this list of users together and display it.
Sounds simple - except how do we then speed up this process by utilizing asynchronous code. We begin to introduce all sorts of nested callbacks, desync's in our JavaScript that are complex to sort out, difficult bug testing, and we start to break DRY as we copy bits and pieces of this code to different files/pages to list different types of data in different ways.
We can solve some of our DRY problems by creating giant API classes that have helper methods for each of these types of calls, but it will still become quite a mess.
What we want is to focus on frontend development - not the API request garbage. By doing this, we are enforcing SRP of the frontend architecture as a whole. The bulk of the frontend code should be dedicated to displaying data, getting input, and showing users responses from their input. It should not be thousands of lines of us making API calls and trying to organize the data. There has to be a simpler way, right?
What if the frontend only had 4 different API requests to make. 1 for authentication, 1 for getting a catalog of endpoints, 1 for getting the status of the system, and finally 1 to facilitate the transfer of bidirectional data. Here is where Apitax/Commandtax comes into play. We now have a single endpoint to send a request to, and that request's payload is commandtax.
Great! Now, instead of a bunch of helper methods all over the place, now we might just have some helper string constants that store frequently used commands. Already much cleaner and more workable. But, this still doesn't solve our DRY problem, SRP, or the callback and desync hell we will face from having to make several requests in a row to accomplish a task.
Enter: Scriptax. Now, any of us can create little self-contained sub module files which do these sequential requests for you. These files are called Scripts. One script might have the responsibility of getting a list of users that follows some set of parameters, and another might call that users script and then using the response returned, it could get a list of posts for each of those users and return them.
Okay, now our frontend only has 1 short line of commandtax which is executing a script. If the scripts are written well, there is no more callback hell, SRP is preserved, DRY is enforced, and the data returned to us will already be in a very workable format. Kaboomskies, you just saved yourself 2 dozen lines of hard to debug JavaScript, and instead, it's a one liner that returns the data already in a workable format
FAQs
Provides utilities and integration code which may be useful when developing various drivers for use within the Apitax framework.
We found that apitaxcore demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.