The invisible REST and web framework

Overview

Kotlin Maven Central CircleCI branch Issues DUB Kotlin Slack #kohesive

Kovert

The invisible REST (and WEB) framework. It is "invisible" since it does not invade your code, and only uses annotations for exception cases (or view rendering).

Kovert is a simple framework that binds your Kotlin classes into your Vert.x 3 (and soon Undertow) routers. It does not try to replace or rebuild these frameworks and only handles the task of providing the "last mile" binding to your controllers. From a fairly normal looking Kotlin class, Kovert can infer the route path and parameters.

This framework is opinionated and optimized for easy coding and default behavior typical of most apps. If you want more control, please use Vertx-Nubes for Vert-x and Kikaha for Undertow, or take a peek at SparkJava.

For starting an application with Kovert, you have two options:

  • Configure, Startup Vert-x, deploy a Vert-x verticle, add your routes with Vert-x Web, and then ask Kovert to bind a controller to an existing route. For that sentence to make sense, you should be familiar with Vertx-Web and the basics of Vertx
  • Alternatively, if you just want to get started without knowing too much, Kovert provides KovertVertx and KovertVerticle classes that can bootstrap a base application, but this acts more as an example starting point from which you should build your own.

In addition, Kovert uses Klutter/Vertx3 module which contains helper classes for working with Vert-x that use Kovenant promises -- including ensuring that the dispatcher for Kovenant is unified with the thread dispatching in Vert.x so that Vert.x context is maintained on dispatch threads, and callbacks come as expected by Vert.x as well. There are additional helpers for Vert.x JSON objects, the logging facade, web, and integration with Injekt, and more.

Maven Dependnecy (Vert.x Version, requires JDK 8 or newer)

Include the dependency in your Gradle / Maven projects that are setup with Kotlin.

Gradle:

compile "uy.kohesive.kovert:kovert-vertx:1.5.+"

Maven:

<dependency>
    <groupId>uy.kohesive.kovert</groupId>
    <artifactId>kovert-vertx</artifactId>
    <version>[1.5.0,1.6.0)</version>
</dependency>

Learn by Example

For a full sample, view the sample REST application to see an example that uses the helper classes KovertVertx and KovertVerticle to startup and run a vertx server using a configuration file.

It helps if you are familiar with Injekt to completely understand the sample. Injekt is not required for use of Kovert and can be bypassed, but it helps! The sample also uses small libraries from Klutter such as to control configuration loading with Typesafe Config.

Binding a Controller

To bind a controller is simple. When you have a route object, call the extension method bindController:

route.bindController(MyControllerClass(), "/api/mystuff")

A controller class is any class that contains methods that are extension functions on a class that you wish to be your dispatch context. So you can either decide that dispatch context is the raw RoutingContext of Vert.x, or you can isolate your code from the raw Vert.x and use simple classes that wrap elements of the RoutingContext to make them available in a type-safe way. Any class that has a 1 parameter constructor of type RoutingContext can be a context class, or RoutingContext itself. An example of a custom context:

class RestContext(private val routingContext: RoutingContext) {
    public val user: User by Delegates.lazy { routingContext.user() }
}

Or one that uses an API key to validate the request using an Auth service provided by Injekt (really you should build a Vert.x auth service, this is just for an example of a context that can reject a request instead of using an intercept):

class ApiKeySecured(private val routingContext: RoutingContext) {
    public val user: User =  Injekt.get<AuthService>()
                 .apiKeyToUser(routingContext.request().getHeader(HttpHeaders.AUTHORIZATION.toString()) ?: "") 
                 ?: throw HttpErrorUnauthorized()
}

With the dispatch object selected, write your controller. Here is the CompanyRestController from the sample app:

class CompanyRestController(val companyService: CompanyService = Injekt.get()) {
    public fun ApiKeySecured.getCompanyByName(name: String): Company = companyService.findCompanyByName(name) ?: throw HttpErrorNotFound()

    public fun ApiKeySecured.putCompanyByName(name: String, company: Company): Company {
        if (!name.equals(company.name, ignoreCase = true)) {
            throw HttpErrorBadRequest()
        }
        companyService.upsertCompany(company)
        return company
    }

    public fun ApiKeySecured.listCompanyByNameEmployees(name: String): List<Person> {
        return companyService.listEmployeesOfCompany(name) ?: throw HttpErrorNotFound()
    }

    public fun ApiKeySecured.findCompaniesNamedByName(name: String): Company = companyService.findCompanyByName(name) ?: throw HttpErrorNotFound()

    public fun ApiKeySecured.findCompaniesLocatedInCountry(country: String): List<Company> {
        val found = companyService.findCompaniesByCountry(country)
        if (found.isEmpty()) throw HttpErrorNotFound()
        return found
    }

    public fun ApiKeySecured.getCompaniesSearch(name: String?, country: String?): Promise<Set<Company>, Exception> {
        return task {
            val byName: List<Company> = name.whenNotNull { companyService.findCompanyByName(name!!) }.whenNotNull { listOf(it) } ?: emptyList()
            val byCountry: List<Company> = country.whenNotNull { companyService.findCompaniesByCountry(country!!) } ?: emptyList()
            (byName + byCountry).toSet()
        }
    }
}

Great, that class looks like it contains normal Kotlin methods, just that they are extension methods on RestContext class. That means each method has access to values of the context and only those values. You can actually have a different context class for each method if you want, and the correct context will be created for dispatching to that method. A context for public methods, one for logged in, another for temporary state during a process flow, etc.

When binding the controller class, HTTP verb and path names are derived from method names unless you use special annotations to override the path, path parameters, HTTP verb and success status code. Kovert is designed to avoid using those annotations altogether, and they should appear ONLY in special cases.

Infering HTTP Verb and Path

So without any annotations, how does Kovert decide the path names and parameters?!?

First, if the name contains underscores it is split on each underscore maintaining case of each fragment in between. Otherwise it camelCase parses the name lower casing each fragment.

After parsing the first fragment indicates the HTTP verb, and the rest are segments of the path. When it encounters special words, it creates path parameters.

The parsing looks like:

// thisIsATestOfSplitting = this is a test of splitting
// AndWhatAboutThis = and what about this
// aURIIsPresent = a uri is present
// SomethingBySomething = something :something
// something20BySomething30 = something20 :something30
// 20ThisAndThat = 20 this and that
// 20thisAndThat = 20this and that
// What_about_underscores = What about underscores
// 20_ThisAndThat_And_What = 20 ThisAndThat And What
// 20________thisAndThat__What = 20 thisAndThat What

Using the prefix part of the method, a HTTP verb is inferred. Obviously prefixes of "get", "put", "post", "delete", "patch" will generate a route that is for the HTTP verb of the same name. You can see in KovertConfig that other aliases are defined such as "list" and "view" for HTTP GET, and "remove" also works same as HTTP DELETE. You can change the alias list in KovertConfig using the addVerbAlias or removeVerbAlias methods. You can also specify aliases in the bindController method as an optional parameter, or as annotations @VerbAliases and @VerbAlias on your controller class. The sample application modifies KovertConfig to add "find" as an alias to HTPT GET:

KovertConfig.addVerbAlias("find", HttpVerb.GET)

Other annotations can be used on classes to tune their behavior and override the path, path parameters and HTTP verbs.

All routing path and parameter decisions are logged to the current logger, so you can easily see the results of the bindController method. The example above, would generate these paths when bound at "/api" route:

Method Verb Path (w/parameters)
getCompanyByName(name: String) GET api/company/:name
putCompanyByName(name: String) PUT api/company/:name
listCompanyByNameEmployees(name: String) GET api/company/:name/employees
findCompaniesNamedByName(name: String) GET api/companies/named/:name
findCompaniesLocatedInCountry(country: String) GET api/companies/located/:country
getCompaniesSearch(name: String, country: String) GET api/companies/search?name=xyz&country=abc

Which I can confirm by viewing my log output (notice it logs from my controller class):

11:41:20.880 [vert.x-eventloop-thread-2] INFO  u.k.k.vertx.sample.CompanyRestController - Binding getCompanyByName to HTTP GET:200 /api/company/:name w/context ApiKeySecured
11:41:20.882 [vert.x-eventloop-thread-2] INFO  u.k.k.vertx.sample.CompanyRestController - Binding listCompanyByNameEmployees to HTTP GET:200 /api/company/:name/employees w/context ApiKeySecured
11:41:20.883 [vert.x-eventloop-thread-2] INFO  u.k.k.vertx.sample.CompanyRestController - Binding findCompaniesNamedByName to HTTP GET:200 /api/companies/named/:name w/context ApiKeySecured
11:41:20.884 [vert.x-eventloop-thread-2] INFO  u.k.k.vertx.sample.CompanyRestController - Binding putCompanyByName to HTTP PUT:200 /api/company/:name w/context ApiKeySecured
11:41:20.885 [vert.x-eventloop-thread-2] INFO  u.k.k.vertx.sample.CompanyRestController - Binding findCompaniesLocatedInCountry to HTTP GET:200 /api/companies/located/:country w/context ApiKeySecured
11:41:20.886 [vert.x-eventloop-thread-2] INFO  u.k.k.vertx.sample.CompanyRestController - Binding getCompaniesSearch to HTTP GET:200 /api/companies/search w/context ApiKeySecured

Path Parameters

Previously, we mentioned that you can use special words to create path parameters, here they are:

word description example result
By next word is path parameter getCompanyByName(name:String) HTTP GET company/:name
In same as By getCompaniesInCountry(country:String) HTTP GET companies/:country
With next word is path segment and then repeated as path parameter getPersonWithName(name:String) HTTP GET person/name/:name

The parameter name will then be bound into your method parameters if one of them has a mathing name. Optional parameters should be nullable.

Soon, we will allow configuring additional replacement rules for word patterns so you can customize the behavior.

Query and Form Parameters

Just add the parameter to your method signature, and it is looked for in the path parameters, query and form parameters. Nothing is needed. You can do simple parameters such as:

public fun MyContext.getPeopleByName(name: String): List<People>

Or you can use complex parameter such as an object:

public fun MyContext.getPeopleByQuery(query: Query): List<People>

In this case, it must receive parameters prefixed by query. such as query.text, query.name, query.country to fill in the values of the Query object in this example.

Body as JSON

If a parameter is not satisfied from path, query, or form parameters, and it has Content-Type of application/json then if it is a complex parameter type it will bound from the body of the request using Jackson data binding.

You can freely mix all parameter types, and the body will only be used if the others do not provide values for a parameter and it will only be used once. An error will result if a complex parameter exists that cannot be satsified from the request.

JSON Response

Any non-String return type becomes JSON automatically using Jackson to serialize the result. This includes classes, lists, maps, and anything else Jackson can detect and serialize as JSON.

Async and Longer Running Handlers

Returning a Kovenant Promise will unwrap the promise when completed and use the resulting value as the response object. This allows async methods. EVERYTHING that isn't immediately resonsive should use Promises otherwise you block Vert.x IO thread, whereas a Promise dispathces on the Vert.x worker thread. In the sample application, you can see in the company controller that the query method uses a promise return type and returns an task {} block of code. You can also create a Deferred instead with more control over your Promise.

public fun RestContext.getCompaniesSearch(name: String?, country: String?): Promise<Set<Company>, Exception> {
    return task {
        val byName: List<Company> = name.whenNotNull { companyService.findCompanyByName(name!!) }.whenNotNull { listOf(it) } ?: emptyList()
        val byCountry: List<Company> = country.whenNotNull { companyService.findCompaniesByCountry(country!!) } ?: emptyList()
        (byName + byCountry).toSet()
    }
}

When using Kovenant promises, please see the section below about Vert.x + Kovenant.

Authorization

Controllers, context classes and controller methods can be protected by a list of Authorities that must be present on the current user or the controller method(s) cannot be called. These are set using the ``@Authorityannotation and provides one or more authorities to match with modeANY` or `ALL`. If authorities are set on the controller then they apply to all methods fo the controller and must match along with any added directly to the context or methods. Same for adding authorities to a context, it must match and any method specific authorities.

Authorization handlers must be set when creating the routes to which the controllers are bound. The authority annotations basically cause the user.isAuthorised(authoriy) method to be called for each authority specified, then combined based on the mode of ANY or ALL. See the Vert.x documentation for Authentication and Authorisation for more on configuration of Vert.x.

An empty @Authority() annotation indicates soley that a valid user must be present, they must be authenticated.

An example:

@Authority("role:admin")
class AdminApiController {
    @Authority("resource:users:read") // requires both role:admin and resource:users:read
    fun SecuredContext.listUsers(): Promise<PageableList<User>, Exception> { ... }

    @Authority("resource:users:write") // requires both role:admin and resource:users:write
    fun SecuredContext.postUser(user: User): Promise<Unit, Exception> { ... }

    // requires only role:admin
    fun SecuredContext.getAdminStats(): Promise<AdminStats, Exception> { ... }

    @Authority("resource:secrets")  // requires role:admin from controller, and role:root from the context, and resource:secrets
    fun RootContext.getSecretThing(): Promise<SuperSecret, Exception> { ... }
}

@Authority("role:root")
class RootContext(val routingContext: RoutingContext) { ... }

HTML Views (or rendering any text based content type)

For rendering HTML or other rendered content you have two options:

  • Return anything of type String and it will set Content-Type of text/html
  • Setup a renderer for any controller method

To use a renderer, add the @Rendered annotation to any controller method, and provide the template name to render. The return value of the method will be used as the model and will be provided to the template. This looks like:

@Rendered("search-results.ftl")
public fun UserContext.getCompaniesSearch(name: String?, country: String?): Promise<CompanySearchResults, Exception> {
    ...
}

In this example, the template engine will be selected by the file extension ".ftl", and the rendering will be passed a model containing and instance of CompanySearchResults.

If the code dynamically changes the template to be used, it can provide a empty @Rendered annotation and return a ModelAndRenderTemplate instance which provides the information about how to render the results.

@Rendered
public fun UserContext.getCompaniesSearch(name: String?, country: String?): Promise<ModelAndRenderTemplate, Exception> {
    return task {
        ...
        ModelAndRenderTemplate(searchResults, "search-${searchType}-results.ftl")
    }
}

Before using rendering, add the dependency for your rendering engine, and register an instance of TemplateEngine via the KovertConfig.registerTemplateEngine() method.

val freemarker = KovertFreemarkerTemplateEngine(configuredFreemarker)
KovertConfig.registerTemplateEngine(freemarker, ".html.ftl", "text/html") // content-type is optional for text/html
KovertConfig.registerTemplateEngine(freemarker, ".xml.ftl", "application/xml")
KovertConfig.registerTemplateEngine(freemarker, ".json.ftl", "application/json")

Template engines are matched from the longest extension to the shortest, so the most specific wins. Note that each extension is registered separately with its appropriate Content-Type type. You can override the content type on any controller method in the @Rendered annotation:

@Rendered("search-results.ftl", "application/xml")
public fun UserContext.getCompaniesSearch(name: String?, country: String?): Promise<CompanySearchResults, Exception> {
  ...
}

WARNING: content type expressed in registration of template engine, or in the @Rendered annotation does not currently affect route matching, but might in the future when it is known at binding time.

Creating your own template engine is simple, just implement a simple interface TemplateEngine, and register an instance of your new engine. The template engine is always run async so it does not block. Most implementations are a few lines of code.

public interface TemplateEngine {
    fun render(template: String, model: Any): String
    // throw unknown exception causes error 500,
    // intentionally throw HttpErrorNotFound if you want a 404
}

NOTE: Some engines may need to wrap the model and the use of the model will vary by engine (some allow it to be at the "root", others always require it to be named).

Available template engines:

compile group: 'uy.kohesive.kovert', name: 'kovert-template-engine-freemarker', version: "${versionKovert}"
compile group: 'uy.kohesive.kovert', name: 'kovert-template-engine-handlebars', version: "${versionKovert}"

It is up to you to configure the raw template system that the engine uses, see the samples above for ideas.

Redirects

For a redirect, just throw an HttpRedirect(toUrl) exception from anywhere in your controller to cause a redirect. Our rational is that redirects are rare, or exception cases so we didn't want to force a standardized return type (such as ActionResult) just for these special cases, which typically never occur in REST api's and rarely in web frontend controllers.

HTTP Errors

The following prebuilt exceptions are available to return HTTP errors. Any other exception will always result in an HTTP status code 500.

open class HttpErrorUnauthorized() : HttpErrorCode("unauthorized", 401)
open class HttpErrorForbidden() : HttpErrorCode("forbidden", 403)
open class HttpErrorBadRequest() : HttpErrorCode("bad request", 400)
open class HttpErrorNotFound() : HttpErrorCode("not found", 404)

open class HttpErrorCode(message: String, val code: Int = 500, causedBy: Throwable? = null)
open class HttpErrorCodeWithBody(message: String, code: Int = 500, val body: Any, causedBy: Throwable? = null) : HttpErrorCode(message, code, causedBy)

The HttpErrorCodeWithBody allows returning a body (String as HTML, complex object as JSON) with the error code.

Intercepts

You can intercept by putting another Vert.x handler before you bind the controller and that handler will be called before the controller, and it can decide whether the next handler is called or not. Or, a controller can implement traits to intercept requests, failures, dispatching and also to create a custom context object factory. See VertxTraits.kt for more information.

Annotations

Name Where Purpose
@VerbAlias Controller Set one method prefix alias to be used only by this controller
@VerbAliases Controller Set a list of method perfix aliases to be used only by this controller
@Location Method Set a specific path for a method, ignoring the method name other than for the prefix to infer the HTTP Verb. Path parameters should be prefixed by a : such as my/path/with/:param
@Verb Method Set the HTTP Verb and default status success code for a method, optionally skipping part of the method name when infering the path
@Authority Controller, Method, Context Set the authorities (role, permission, etc) required for the controller, context or method. And the mode to match ANY or ALL

If is typical to use @Location and @Verb together on a method, although they can be used individually.

If you use the @Verb annotation on a method, by default the prefix of the method name is parsed and thrown away so it really can be anything. Or if you want to use the prefix as the first path segment you may use the skipPrefix parameter with value false such as @Verb(HttpVerb.GET, skipPrefix = false) public fun SomeContext.someHappyMethod(): MyResult would bind to some/happy/method whereas skipPrefix = true would bind to happy/method.

Kovert Helpers

Vert.x + Kovenant Promises

For using Vert.x with Kovenant promises, you should launch Vert.x using one of the Klutter/Vertx3 helper functions. If you are NOT using these methods, then call VertxInit.ensure() before using your first Kovenant promise, and before using anything that involves data binding with Kovert. Otherwise, using a helper startup function will do this for you automatically. Note that you can also use the prettier task { } instead of Vert.x executeBlocking() when using Kovenant integration.

See Klutter/Vertx3 for all Vert.x helper functions include JSON, Vertx-Web, Logging and Injekt modules.

Vert.x and KovertVerticle startup

Really, you should configure and launch Vert.x yourself (use helpers above, Klutter for config loading, etc.). But to act as both a sample, and a quick start helper, There are two classes you can use to startup Vert.x enabled for everything described in this documentation. Or use these as a samples to write your own:

The sample application App.kt shows one use of these classes.

Injekt

Both for setting up JSON integrated with Kotlin, JDK 8 and Vert.x; and for integrated logging you may import Injekt modules.

Importing module VertxInjektables will provide an ObjectMapper singleton available for Jackson data binding that is shared with Vert.x, and Kovenant will be initialized correctly so that promises and async calls work in conjunction with Vert.x thread dispathcing, and you will have a logger factory configured routing any of your injected logging calls through the Vertx logging Facade. Alterantively you can import the VertxWithSlf4jInjektables module for the same benefits, although your logging factory will be setup to be direct to SLF4j for application code.

See the sample application App.kt which uses Injekt for configuration, KovertVertx and KovertVerticle classes to launch Vert.x and Kovert, data binding, logging and providing services.

More Examples

View the sample application, and the unit tests for more combinations of the previously described topics.

Road Map (random order)

  • Undertow support as alternative to Vert.x
  • SparkJava support as alternative to Vert.x and Undertow
  • Configurable clauses in method names for substitution patterns (i.e. "By", "In", "With" are substitution patterns)
  • With View support, people will want to ask for the HREF from a given controller method, should be able to provide that in Kotlin M13, or can provide using the val getSomeThing = fun MyContext.(param: String): MyObject { ... } form of declaring a controller method already since MyClass::getSomething can reference that value, whereas in the other form, it is not referenceable in M12.
  • Ignore annotation for extension methods in controller that are not desired

Special Thanks

YourKit logo

YourKit supports open source projects with its full-featured Java Profiler. YourKit, LLC is the creator of YourKit Java Profiler and YourKit .NET Profiler, innovative and intelligent tools for profiling Java and .NET applications.

Comments
  • enhancement request: add maven packages for freemarker and handlebars support

    enhancement request: add maven packages for freemarker and handlebars support

    or better directions for integrating w/ an app.

    Including only compile "uy.kohesive.kovert:kovert-vertx:0.13.+" isn't enough to pull freemarker in or the small class to use it.

    I prefer HandleBars though...beats Freemarker in a bunch of benchmark tests ;-)

    opened by kenkyee 16
  • logout in example web app doesn't log out

    logout in example web app doesn't log out

    To reproduce:

    • start example kovert app
    • go to localhost:8080
    • click on login link
    • type in franky/123 for creds as prompted
    • click on logout link
    • click on login link again (it should prompt for a username/password at this point but doesn't)
    opened by kenkyee 2
  • Kovert doesn't allow json body on 400

    Kovert doesn't allow json body on 400

    Kovert doesn't seem to allow returning an application/json body with a 400 error even though HTTP allows and actually strongly recommends this. Sometimes on an invalid request way more details are needed than just an http code and message.

    Here is the relevant part of http spec:

    10.4 Client Error 4xx

    The 4xx class of status code is intended for cases in which the client seems to have erred. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition. These status codes are applicable to any request method. User agents SHOULD display any included entity to the user.

    If the client is sending data, a server implementation using TCP SHOULD be careful to ensure that the client acknowledges receipt of the packet(s) containing the response, before the server closes the input connection. If the client continues sending data to the server after the close, the server's TCP stack will send a reset packet to the client, which may erase the client's unacknowledged input buffers before they can be read and interpreted by the HTTP application.

    Note that all caps SHOULD include and entity containing an explanation of the error.

    A good example of where this is needed and used effectively is card validation error codes with Stripe:

    https://stripe.com/docs/api/java#errors

    opened by adambrown 1
  • Kovert isn't respecting defaulted query params

    Kovert isn't respecting defaulted query params

    e.g.

    /**
     *
     *  HTTP GET /path/thing/:thingid/subthing/subsubthings?size=50&forwardMarker=invoice_id
     *
     */
    fun Context.listThingByThingidSubthingSubsubthing(thingid: String, size: Int = 50, forwardMarker: String? = null): Promise<WithScrolling<String, List<Thing>>, Exception> {
    

    makes the rest client always provide size and forwardMarker params even though there are sensible defaults that could be used.

    opened by adambrown 1
  • Data binding should be able to inject (via Injekt) missing values

    Data binding should be able to inject (via Injekt) missing values

    When data binding parameters, some should be able to be injected from Injekt. This could be done with default parameter values, assuming Kotlin reflection will allow us to detect and use the default-able form of a method. This should be possible given reported issues:

    KT-8824 KT-8827

    That also lets us know which of these already have defaults values coming from Kotlin.

    enhancement 
    opened by apatrida 1
  • Kotlin M13 support

    Kotlin M13 support

    It's coming, and we have reflection changes. Here are the issues we are tracking:

    Problem 
    opened by apatrida 0
  • HREF support from a controller member that generated a route

    HREF support from a controller member that generated a route

    Given a reference "MyClass::someMethod" that is a bound controller method, return the internal and external URL HREF. This can be done now given a controller that adds methods in the form:

    val getSomeThing = fun MyContext.(param: String): MyObject { ... } 
    

    Since Kotlin allow that reference, and the binder already supports binding to it. Just need to remember the information from the route so it can be looked up again.

    The other form:

    fun MyContext.getSomeThing(param: String): MyObject { ... }
    

    Cannot yet work because Kotlin doesn't allow reference "MyClass::getSomeThing" in that form (It is both an extension function and a member function). Hopefully in M13, KT-8835 will be resolved allowing this.

    enhancement 
    opened by apatrida 2
  • Configurable URL transformation clauses (similar to By, In, With)

    Configurable URL transformation clauses (similar to By, In, With)

    Allow the user of the framework with configure their own transformations for paths and path parameters. Similar to how By, In and With work now, but more flexible.

    enhancement 
    opened by apatrida 0
Owner
Kohesive
A kohesive set of Kotlin libraries
Kohesive
Find Security Bugs is the SpotBugs plugin for security audits of Java web applications

The SpotBugs plugin for security audits of Java web applications and Android applications. (Also work with Kotlin, Groovy and Scala projects)

OWASP Find Security Bugs 2k Jan 6, 2023
Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.

Themis provides strong, usable cryptography for busy people General purpose cryptographic library for storage and messaging for iOS (Swift, Obj-C), An

Cossack Labs 1.6k Dec 29, 2022
A Java ePub reader and parser framework for Android.

FolioReader-Android is an EPUB reader written in Java and Kotlin. Features Custom Fonts Custom Text Size Themes / Day mode / Night mode Text Highlight

FolioReader 2.1k Jan 3, 2023
UNIX-like reverse engineering framework and command-line toolset

Radare2: The Libre Unix-Like Reverse Engineering Framework See the Releases page for downloads. The current git master branch is 5.7.7, next will be 5

radare org 17.4k Jan 9, 2023
Mobile Security Framework (MobSF)

Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis.

Mobile Security Framework 13.2k Jan 4, 2023
Soot - A Java optimization framework

Using Soot? Let us know about it! We are regularly applying for funding to help us maintain Soot. You can help us immensely by letting us know about p

Soot Program Analysis Framework 2.5k Jan 2, 2023
MiHawk 🦅👁️ is simple and secure 🔒 Android Library to store and retrieve pair of key-value data with encryption , internally it use jetpack DataStore Preferences 💽 to store data.

MiHawk MiHawk ?? ??️ is simple and secure ?? Android Library to store and retrieve pair of key-value data with encryption , internally it use jetpack

Nedal Hasan Ibrahem 5 Sep 3, 2022
Grab’n Run, a simple and effective Java Library for Android projects to secure dynamic code loading.

Grab’n Run, a simple and effective Java Library for Android projects to secure dynamic code loading.

Luca Falsina 418 Dec 29, 2022
Android virtual machine and deobfuscator

Simplify Generic Android Deobfuscator Simplify virtually executes an app to understand its behavior and then tries to optimize the code so that it beh

Caleb Fenton 4.1k Dec 25, 2022
BlackDex is an Android unpack tool, it supports Android 5.0~12 and need not rely to any environment. BlackDex can run on any Android mobile phones or emulators, you can unpack APK File in several seconds.

BlackDex is an Android unpack tool, it supports Android 5.0~12 and need not rely to any environment. BlackDex can run on any Android mobile phones or emulators, you can unpack APK File in several seconds.

null 4.3k Jan 2, 2023
A simple and opinionated AES encrypt / decrypt Ruby gem that just works.

AESCrypt - Simple AES encryption / decryption for Ruby AESCrypt is a simple to use, opinionated AES encryption / decryption Ruby gem that just works.

Gurpartap Singh 158 Oct 18, 2022
Simple API to perform AES encryption on Android. This is the Android counterpart to the AESCrypt library Ruby and Obj-C (with the same weak security defaults :( ) created by Gurpartap Singh. https://github.com/Gurpartap/aescrypt

AESCrypt-Android Simple API to perform AES encryption on Android with no dependancies. This is the Android counterpart to the AESCrypt library Ruby an

Scott Alexander-Bown 636 Dec 18, 2022
A program to flip every private, protected and package-private access flag to public in an Android dex file!

DexExposed A program to flip every private, protected and package-private access flag to public in an Android dex file! Building Simply run gradle mak

John Doe 2 Aug 29, 2021
A simple android app that parses its own signature and displays it

SigDisplayer Usage Download the release APK or clone the repository and compile yourself. Sign the APK with your preferred keystore. Install and open

Jonah 5 Oct 18, 2022
A program analysis tool to find cryptographic misuse in Java and Android.

A program analysis tool to find cryptographic misuse in Java and Android.

null 92 Dec 15, 2022
CRYLOGGER: Detecting Crypto Misuses for Android and Java Apps Dynamically

CRYLOGGER: Detecting Crypto Misuses for Android and Java Apps Dynamically

Luca Piccolboni 139 Dec 12, 2022
A tool translate a apk file to stantard android project include so hook api and il2cpp c++ scaffolding when apk is a unity il2cpp game. Write code on a apk file elegantly.

FakerAndroid (FakerAndroid.jar or FakerAndroid-AS) A tool translate a apk file to stantard android project include so hook api and il2cpp c++ scaffold

null 231 Dec 29, 2022
Burp extension to create target specific and tailored wordlist from burp history.

Burp extension to create target specific and tailored wordlist from burp history.

Dexter0us 173 Jan 2, 2023