Parcourir la source

WIP. adding more openapi docs, normalizing

tags/v1.4.37
Jonathan Cobb il y a 4 ans
Parent
révision
632a442052
15 fichiers modifiés avec 224 ajouts et 71 suppressions
  1. +1
    -0
      bubble-server/src/main/java/bubble/ApiConstants.java
  2. +3
    -1
      bubble-server/src/main/java/bubble/model/AppLinks.java
  3. +19
    -0
      bubble-server/src/main/java/bubble/model/BasicAppLinks.java
  4. +3
    -2
      bubble-server/src/main/java/bubble/resources/EntityConfigsResource.java
  5. +2
    -1
      bubble-server/src/main/java/bubble/resources/IdentityResource.java
  6. +3
    -2
      bubble-server/src/main/java/bubble/resources/SearchResource.java
  7. +2
    -1
      bubble-server/src/main/java/bubble/resources/TagsResource.java
  8. +6
    -7
      bubble-server/src/main/java/bubble/resources/account/AccountOwnedResource.java
  9. +4
    -3
      bubble-server/src/main/java/bubble/resources/account/AccountPromotionsResource.java
  10. +21
    -21
      bubble-server/src/main/java/bubble/resources/account/AccountsResource.java
  11. +157
    -14
      bubble-server/src/main/java/bubble/resources/account/AuthResource.java
  12. +0
    -18
      bubble-server/src/main/java/bubble/server/BasicAppLinks.java
  13. +1
    -0
      bubble-server/src/main/java/bubble/server/BubbleConfiguration.java
  14. +1
    -0
      bubble-server/src/main/resources/bubble-config.yml
  15. +1
    -1
      utils/cobbzilla-wizard

+ 1
- 0
bubble-server/src/main/java/bubble/ApiConstants.java Voir le fichier

@@ -300,6 +300,7 @@ public class ApiConstants {
public static final String API_TAG_SEARCH = "search";
public static final String API_TAG_BACKUP_RESTORE = "backup and restore";
public static final String API_TAG_NODE = "node";
public static final String API_TAG_NODE_MANAGER = "node manager";

public static String getToken(String json) {
if (json == null) return null;


bubble-server/src/main/java/bubble/server/AppLinks.java → bubble-server/src/main/java/bubble/model/AppLinks.java Voir le fichier

@@ -2,15 +2,17 @@
* Copyright (c) 2020 Bubble, Inc. All rights reserved.
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/
*/
package bubble.server;
package bubble.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;

import java.util.HashMap;
import java.util.Map;

@Schema
public class AppLinks extends BasicAppLinks {

@JsonIgnore @Getter @Setter private Map<String, BasicAppLinks> locale = new HashMap<>();

+ 19
- 0
bubble-server/src/main/java/bubble/model/BasicAppLinks.java Voir le fichier

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2020 Bubble, Inc. All rights reserved.
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/
*/
package bubble.model;

import lombok.Getter;
import lombok.Setter;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECField;

public class BasicAppLinks {

@ECField @Getter @Setter private String ios;
@ECField @Getter @Setter private String android;
@ECField @Getter @Setter private String windows;
@ECField @Getter @Setter private String macosx;
@ECField @Getter @Setter private String linux;

}

+ 3
- 2
bubble-server/src/main/java/bubble/resources/EntityConfigsResource.java Voir le fichier

@@ -35,6 +35,7 @@ import static bubble.ApiConstants.ENTITY_CONFIGS_ENDPOINT;
import static java.lang.Boolean.TRUE;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.util.io.FileUtil.abs;
import static org.cobbzilla.util.string.StringUtil.packagePath;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
@@ -57,7 +58,7 @@ public class EntityConfigsResource extends AbstractEntityConfigsResource {
description="Set a configuration parameter to `true`",
parameters={@Parameter(name="param", description="the name of the parameter to set")},
responses={
@ApiResponse(description="the value that was set",
@ApiResponse(responseCode=SC_OK, description="the value that was set",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="should always return true", value="true")
}
@@ -79,7 +80,7 @@ public class EntityConfigsResource extends AbstractEntityConfigsResource {
@Parameter(name="value", description="the value to set the parameter to")
},
responses={
@ApiResponse(description="the value that was set",
@ApiResponse(responseCode=SC_OK, description="the value that was set",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="if the value was the String 'foo'", value="\"foo\"")
}


+ 2
- 1
bubble-server/src/main/java/bubble/resources/IdentityResource.java Voir le fichier

@@ -30,6 +30,7 @@ import java.util.Map;

import static bubble.ApiConstants.ID_ENDPOINT;
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.API_TAG_UTILITY;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY;
@@ -53,7 +54,7 @@ public class IdentityResource {
description="Searches all model objects by ID. The id parameter is typically a UUID or name",
parameters={@Parameter(name="id", description="an identifier (typically UUID or name) to search for")},
responses={
@ApiResponse(description="a JSON object where the property names are entity types, and a property's corresponding value is the object of that type found with the given ID",
@ApiResponse(responseCode=SC_OK, description="a JSON object where the property names are entity types, and a property's corresponding value is the object of that type found with the given ID",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="usually a UUID only matches one object", value="{\"CloudService\": {\"uuid\": \"the-ID-you-searched-for\", \"other-cloud-service-fields\": \"would-be-shown\"}}"),
@ExampleObject(name="a UUID for an Account also matches the AccountPolicy", value="{\"Account\": {\"uuid\": \"the-ID-you-searched-for\", \"other-account-fields\": \"would-be-shown\"}, \"AccountPolicy\": {\"uuid\": \"the-ID-you-searched-for\", \"other-policy-fields\": \"would-be-shown\"}}"),


+ 3
- 2
bubble-server/src/main/java/bubble/resources/SearchResource.java Voir le fichier

@@ -23,6 +23,7 @@ import javax.ws.rs.core.Response;

import static bubble.ApiConstants.*;
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.wizard.resources.ResourceUtil.ok;
import static org.cobbzilla.wizard.resources.ResourceUtil.userPrincipal;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY;
@@ -50,7 +51,7 @@ public class SearchResource {
@Parameter(name=Q_SORT, description="sort field. prefix with + or - to indicate ascending/descending")
},
responses={
@ApiResponse(description="a SearchResults object, or if meta was true then a SqlViewField[] array")
@ApiResponse(responseCode=SC_OK, description="a SearchResults object, or if meta was true then a SqlViewField[] array")
}
)
public Response search(@Context Request req,
@@ -80,7 +81,7 @@ public class SearchResource {
@Parameter(name=Q_SORT, description="sort field. prefix with + or - to indicate ascending/descending")
},
responses={
@ApiResponse(description="a SearchResults object, or if meta was true then a SqlViewField[] array")
@ApiResponse(responseCode=SC_OK, description="a SearchResults object, or if meta was true then a SqlViewField[] array")
}
)
public Response search(@Context Request req,


+ 2
- 1
bubble-server/src/main/java/bubble/resources/TagsResource.java Voir le fichier

@@ -22,6 +22,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY;

@@ -46,7 +47,7 @@ public class TagsResource {
summary="Set a tag",
description="Set a tag",
parameters={@Parameter(name="name", description="name of the tag")},
responses={@ApiResponse(description="a BubbleTags object representing the current list of tags")}
responses={@ApiResponse(responseCode=SC_OK, description="a BubbleTags object representing the current list of tags")}
)
public Response set(@Context ContainerRequest ctx,
@PathParam("name") String name,


+ 6
- 7
bubble-server/src/main/java/bubble/resources/account/AccountOwnedResource.java Voir le fichier

@@ -29,8 +29,7 @@ import java.util.List;

import static bubble.ApiConstants.API_TAG_ACCOUNT_OBJECTS;
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_NOT_FOUND;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_PRECONDITION_FAILED;
import static org.cobbzilla.util.http.HttpStatusCodes.*;
import static org.cobbzilla.util.reflect.ReflectionUtil.getFirstTypeParam;
import static org.cobbzilla.util.reflect.ReflectionUtil.instantiate;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
@@ -69,7 +68,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned
tags={API_TAG_ACCOUNT_OBJECTS},
summary="List objects",
description="List objects",
responses={@ApiResponse(description="an array of objects")}
responses={@ApiResponse(responseCode=SC_OK, description="an array of objects")}
)
public Response listEntities(@Context Request req,
@Context ContainerRequest ctx) {
@@ -141,7 +140,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned
summary="Find by identifier",
description="Find by identifier",
responses={
@ApiResponse(description="the object, if found"),
@ApiResponse(responseCode=SC_OK, description="the object, if found"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="if the object does not exist")
}
)
@@ -174,7 +173,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned
summary="Create a new object",
description="Create a new object. If validation errors occur, status "+SC_PRECONDITION_FAILED+" is returned and the response will contain an array of errors. Within each error, the `messageTemplate` field refers to messages that can be localized using the /messages resource",
responses={
@ApiResponse(description="the object that was created"),
@ApiResponse(responseCode=SC_OK, description="the object that was created"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="validation errors", value="[{\"messageTemplate\": \"some.symbolic.error\", \"message\": \"some default English message\"}]")
@@ -216,7 +215,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned
description="Update an new object. For many types, the object will be created if it does not exist. If validation errors occur, status "+SC_PRECONDITION_FAILED+" is returned and the response will contain an array of errors. Within each error, the `messageTemplate` field refers to messages that can be localized using the /messages resource",
parameters={@Parameter(name="id", description="the UUID (or name, if allowed) of the object to update")},
responses={
@ApiResponse(description="the object that was updated"),
@ApiResponse(responseCode=SC_OK, description="the object that was updated"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="no object exists with the given id"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred",
content={@Content(mediaType=APPLICATION_JSON, examples={
@@ -253,7 +252,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned
description="Delete an existing object",
parameters={@Parameter(name="id", description="the UUID (or name, if allowed) of the object to delete")},
responses={
@ApiResponse(description="the object that was deleted"),
@ApiResponse(responseCode=SC_OK, description="the object that was deleted"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="no object exists with the given id")
}
)


+ 4
- 3
bubble-server/src/main/java/bubble/resources/account/AccountPromotionsResource.java Voir le fichier

@@ -19,6 +19,7 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY;

@@ -36,7 +37,7 @@ public class AccountPromotionsResource {
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
summary="List promotions for account",
description="List promotions for account",
responses={@ApiResponse(description="an array of Promotion objects owned by the Account")}
responses={@ApiResponse(responseCode=SC_OK, description="an array of Promotion objects owned by the Account")}
)
public Response listPromotions(@Context Request req,
@Context ContainerRequest ctx) {
@@ -49,7 +50,7 @@ public class AccountPromotionsResource {
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
summary="Add a promotion to an account. Must be admin.",
description="Add a promotion to an account. Must be admin.",
responses={@ApiResponse(description="an array of Promotion objects owned by the Account")}
responses={@ApiResponse(responseCode=SC_OK, description="an array of Promotion objects owned by the Account")}
)
public Response adminAddPromotion(@Context Request req,
@Context ContainerRequest ctx,
@@ -63,7 +64,7 @@ public class AccountPromotionsResource {
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
summary="Remove a promotion from an account. Must be admin.",
description="Remove a promotion from an account. Must be admin.",
responses={@ApiResponse(description="an array of Promotion objects owned by the Account")}
responses={@ApiResponse(responseCode=SC_OK, description="an array of Promotion objects owned by the Account")}
)
public Response adminRemovePromotion(@Context Request req,
@Context ContainerRequest ctx,


+ 21
- 21
bubble-server/src/main/java/bubble/resources/account/AccountsResource.java Voir le fichier

@@ -83,7 +83,7 @@ public class AccountsResource {
summary="List all accounts",
description="List all accounts. Must be admin.",
responses={
@ApiResponse(description="an array of Account objects"),
@ApiResponse(responseCode=SC_OK, description="an array of Account objects"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin")
}
)
@@ -98,7 +98,7 @@ public class AccountsResource {
summary="Find account by UUID or email. Non-admins can only find themselves.",
description="Find account by UUID or email. Non-admins can only find themselves.",
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was found", ref="#/components/schemas/Account"),
@ApiResponse(responseCode=SC_OK, description="the Account object that was found"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin")
}
)
@@ -114,7 +114,7 @@ public class AccountsResource {
summary="Create a new account",
description="Create a new account. Must be admin.",
responses={
@ApiResponse(description="the Account object that was just created", ref="#/components/schemas/Account"),
@ApiResponse(responseCode=SC_OK, description="the Account object that was just created"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin")
}
)
@@ -178,7 +178,7 @@ public class AccountsResource {
description="Download all data for user. Must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="a Map<String, List<String>> of all user data"),
@ApiResponse(responseCode=SC_OK, description="a Map<String, List<String>> of all user data"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin")
}
)
@@ -201,7 +201,7 @@ public class AccountsResource {
description="Update an account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was updated", ref="#/components/schemas/Account"),
@ApiResponse(responseCode=SC_OK, description="the Account object that was updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is updating any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
}
@@ -235,7 +235,7 @@ public class AccountsResource {
description="List all launch statuses for an account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="a List<NodeProgressMeterTick> representing the status of active launch operations"),
@ApiResponse(responseCode=SC_OK, description="a List<NodeProgressMeterTick> representing the status of active launch operations"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
}
)
@@ -261,7 +261,7 @@ public class AccountsResource {
description="View the AccountPolicy for an account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="an AccountPolicy object", ref="#/components/schemas/AccountPolicy"),
@ApiResponse(responseCode=SC_OK, description="an AccountPolicy object"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
}
)
@@ -280,7 +280,7 @@ public class AccountsResource {
description="Update the AccountPolicy for an account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="an AccountPolicy object", ref="#/components/schemas/AccountPolicy"),
@ApiResponse(responseCode=SC_OK, description="an AccountPolicy object"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
}
@@ -310,7 +310,7 @@ public class AccountsResource {
description="Create or update an AccountContact in the AccountPolicy. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="the AccountContact object that was created or updated", ref="#/components/schemas/AccountPolicy"),
@ApiResponse(responseCode=SC_OK, description="the AccountContact object that was created or updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
}
@@ -351,7 +351,7 @@ public class AccountsResource {
description="Send verification message for an AccountContact. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="the AccountContact object that was created or updated", ref="#/components/schemas/AccountContact"),
@ApiResponse(responseCode=SC_OK, description="the AccountContact object that was created or updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
}
)
@@ -382,7 +382,7 @@ public class AccountsResource {
@Parameter(name="info", description="the contact information, for example an email address or phone number")
},
responses={
@ApiResponse(description="the AccountContact object", ref="#/components/schemas/AccountContact"),
@ApiResponse(responseCode=SC_OK, description="the AccountContact object"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="no AccountContact exists with the given type and info")
}
@@ -409,7 +409,7 @@ public class AccountsResource {
@Parameter(name="info", description="the contact information, for example an email address or phone number")
},
responses={
@ApiResponse(description="the AccountContact object that was deleted", ref="#/components/schemas/AccountContact"),
@ApiResponse(responseCode=SC_OK, description="the AccountContact object that was deleted"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
}
)
@@ -433,7 +433,7 @@ public class AccountsResource {
description="Delete TOTP authenticator AccountContact from an AccountPolicy. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="the AccountPolicy object that was updated", ref="#/components/schemas/AccountPolicy"),
@ApiResponse(responseCode=SC_OK, description="the AccountPolicy object that was updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
}
)
@@ -463,7 +463,7 @@ public class AccountsResource {
@Parameter(name="uuid", description="UUID of the AccountContact")
},
responses={
@ApiResponse(description="the AccountPolicy object that was updated", ref="#/components/schemas/AccountPolicy"),
@ApiResponse(responseCode=SC_OK, description="the AccountPolicy object that was updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
}
)
@@ -486,7 +486,7 @@ public class AccountsResource {
description="Request deletion of an Account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="the AccountMessage object that was sent", ref="#/components/schemas/AccountMessage"),
@ApiResponse(responseCode=SC_OK, description="the AccountMessage object that was sent"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
}
)
@@ -516,7 +516,7 @@ public class AccountsResource {
description="Change password for an account. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="the Account object that was updated", ref="#/components/schemas/Account"),
@ApiResponse(responseCode=SC_OK, description="the Account object that was updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
}
@@ -595,7 +595,7 @@ public class AccountsResource {
description="Delete an Account. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="the Account object that was deleted", ref="#/components/schemas/Account"),
@ApiResponse(responseCode=SC_OK, description="the Account object that was deleted"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
}
)
@@ -634,7 +634,7 @@ public class AccountsResource {
description="Get status of mitmproxy. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="returns true if mitmproxy is enabled, false otherwise",
@ApiResponse(responseCode=SC_OK, description="returns true if mitmproxy is enabled, false otherwise",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="mitmproxy is enabled", value="true"),
@ExampleObject(name="mitmproxy is disabled", value="false")
@@ -657,7 +657,7 @@ public class AccountsResource {
description="Enable mitmproxy. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="returns true if mitmproxy is enabled, false otherwise",
@ApiResponse(responseCode=SC_OK, description="returns true if mitmproxy is enabled, false otherwise",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="mitmproxy is enabled", value="true"),
@ExampleObject(name="mitmproxy is disabled", value="false")
@@ -680,7 +680,7 @@ public class AccountsResource {
description="Disable mitmproxy. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={
@ApiResponse(description="returns true if mitmproxy is enabled, false otherwise",
@ApiResponse(responseCode=SC_OK, description="returns true if mitmproxy is enabled, false otherwise",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="mitmproxy is enabled", value="true"),
@ExampleObject(name="mitmproxy is disabled", value="false")
@@ -758,7 +758,7 @@ public class AccountsResource {
summary="List all device types",
description="List all device types",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={@ApiResponse(description="returns an array of Strings, each a BubbleDeviceType enum value")}
responses={@ApiResponse(responseCode=SC_OK, description="returns an array of Strings, each a BubbleDeviceType enum value")}
)
public Response getDeviceTypes(@Context ContainerRequest ctx) {
return ok(BubbleDeviceType.getSelectableTypes());


+ 157
- 14
bubble-server/src/main/java/bubble/resources/account/AuthResource.java Voir le fichier

@@ -135,7 +135,7 @@ public class AuthResource {
@Operation(tags={API_TAG_UTILITY},
summary="Read public system configuration",
description="Read public system configuration",
responses={@ApiResponse(description="a Map<String, Object> of public system configuration settings")}
responses={@ApiResponse(responseCode=SC_OK, description="a Map<String, Object> of public system configuration settings")}
)
public Response getPublicSystemConfigs(@Context ContainerRequest ctx) {
return ok(configuration.getPublicSystemConfigs());
@@ -171,7 +171,7 @@ public class AuthResource {
summary="Determine if the API has been activated",
description="Determine if the API has been activated",
responses={
@ApiResponse(description="returns true if API is activated, false otherwise",
@ApiResponse(responseCode=SC_OK, description="returns true if API is activated, false otherwise",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="Bubble is activated", value="true"),
@ExampleObject(name="Bubble has not been activated", value="false")
@@ -184,7 +184,7 @@ public class AuthResource {
@Operation(tags={API_TAG_ACTIVATION},
summary="Get activation default configuration",
description="Get activation default configuration",
responses={@ApiResponse(description="returns an array of CloudService[] representing the default CloudServices and their settings")}
responses={@ApiResponse(responseCode=SC_OK, description="returns an array of CloudService[] representing the default CloudServices and their settings")}
)
public Response getActivationConfigs(@Context ContainerRequest ctx) {
final Account caller = optionalUserPrincipal(ctx);
@@ -198,7 +198,7 @@ public class AuthResource {
summary="Perform one-time activation",
description="Perform one-time activation",
responses={
@ApiResponse(description="the Account object for the initial admin account, with a new session token"),
@ApiResponse(responseCode=SC_OK, description="the Account object for the initial admin account, with a new session token"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and activation has already been completed"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred: activation has already been completed, or there were errors processing the ActivationRequest object")
}
@@ -326,7 +326,7 @@ public class AuthResource {
summary="Register a new Account, starts a new API session.",
description="Register a new Account, starts a new API session.",
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was registered", ref="#/components/schemas/Account"),
@ApiResponse(responseCode=SC_OK, description="the Account object that was registered, `token` property holds session token"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
}
)
@@ -443,7 +443,7 @@ public class AuthResource {
description="Login an Account, starts a new API session.",
parameters={@Parameter(name="k", description="for a new Bubble that was launched with the lock enabled, the unlock key is required for the first login")},
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in", ref="#/components/schemas/Account"),
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
}
)
@@ -524,7 +524,7 @@ public class AuthResource {
description="Login an Account using an existing session token, starts a new API session. If an existing session exists, it is invalidated",
parameters={@Parameter(name="session", description="the session token to use for logging in")},
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in", ref="#/components/schemas/Account"),
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
}
)
@@ -592,7 +592,7 @@ public class AuthResource {
summary="Called between Bubbles to verify RSA keys",
description="Called between Bubbles to verify RSA keys",
responses={
@ApiResponse(responseCode=SC_OK, description="an RsaMessage object representing the encrypted challenge response", ref="#/components/schemas/RsaMessage"),
@ApiResponse(responseCode=SC_OK, description="an RsaMessage object representing the encrypted challenge response"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="some error occurred, check response")
}
)
@@ -654,7 +654,7 @@ public class AuthResource {
summary="Re-key a node. Must be admin. Creates a new NodeKey that, being newest, will be the one the node starts using",
description="Re-key a node. Must be admin. Creates a new NodeKey that, being newest, will be the one the node starts using",
responses={
@ApiResponse(description="the NodeKey that was created", ref="#/components/schemas/BubbleNodeKey"),
@ApiResponse(responseCode=SC_OK, description="the NodeKey that was created"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
}
@@ -727,6 +727,19 @@ public class AuthResource {
}

@POST @Path(EP_APPROVE+"/{token}")
@Operation(tags={API_TAG_AUTH},
summary="Approve a request",
description="Approve a request. The token comes from an email or SMS message sent to the user.",
parameters={@Parameter(name="token", description="the confirmation token")},
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="if no login requested, returns an empty response", value=""),
@ExampleObject(name="if login requested, returns an Account object with either a valid session token ('token' property) or additional auth factors required (check 'multifactorAuth' property)")
})}),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid")
}
)
public Response approve(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("token") String token,
@@ -764,6 +777,18 @@ public class AuthResource {
}

@POST @Path(EP_AUTHENTICATOR)
@Operation(tags={API_TAG_AUTH},
summary="Approve a TOTP request",
description="Approve a TOTP request. The token comes the end user's authenticator app.",
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="if no login requested, returns an empty response", value=""),
@ExampleObject(name="if login requested, returns an Account object with either a valid session token ('token' property) or additional auth factors required (check 'multifactorAuth' property)")
})}),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid")
}
)
public Response authenticator(@Context Request req,
@Context ContainerRequest ctx,
AuthenticatorRequest request) {
@@ -816,15 +841,38 @@ public class AuthResource {
}

@DELETE @Path(EP_AUTHENTICATOR)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_AUTH},
summary="Flush authenticator tokens",
description="Flush authenticator tokens. The next operation that requires TOTP auth will require the user to re-authenticate.",
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="returns an empty JSON object", value="{}")
})}),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid")
}
)
public Response flushAuthenticatorTokens(@Context Request req,
@Context ContainerRequest ctx) {
@Context ContainerRequest ctx) {
final Account caller = userPrincipal(ctx);
authenticatorService.flush(caller.getToken());
return ok_empty();
}

@POST @Path(EP_DENY+"/{token}")
@Operation(tags={API_TAG_AUTH},
summary="Deny a request",
description="Deny a request. The token comes from an email or SMS message sent to the user.",
parameters={@Parameter(name="token", description="the confirmation token")},
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="returns the denial AccountMessage")
})}),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid")
}
)
public Response deny(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("token") String token) {
@@ -838,6 +886,15 @@ public class AuthResource {

@GET @Path(EP_CA_CERT)
@Produces(CONTENT_TYPE_ANY)
@Operation(tags={API_TAG_UTILITY},
summary="Get the CA Certificate for this Bubble",
description="Get the CA Certificate for this Bubble. Response body is the certificate itself, in a format determined by deviceType or type",
parameters={
@Parameter(name="deviceType", description="the device type"),
@Parameter(name="type", description="the certificate type")
},
responses={@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success, response body is certificate")}
)
public Response getCaCert(@Context Request req,
@Context ContainerRequest ctx,
@QueryParam("deviceType") BubbleDeviceType deviceType,
@@ -867,6 +924,13 @@ public class AuthResource {
}

@GET @Path(EP_KEY)
@Operation(tags={API_TAG_UTILITY},
summary="Get the Node Key for this Bubble",
description="Get the Node Key for this Bubble",
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success")
}
)
public Response getNodeKey(@Context Request req,
@Context ContainerRequest ctx) {
final BubbleNode thisNode = configuration.getThisNode();
@@ -886,7 +950,16 @@ public class AuthResource {
}

@GET @Path(EP_LOGOUT)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_AUTH},
summary="Logout",
description="Logout of the current session, or logout of all sessions everywhere if the `all` parameter is true.",
parameters={@Parameter(name="all", description="logout of all sessions everywhere")},
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="If there is no current session to log out of")
}
)
public Response logout(@Context ContainerRequest ctx,
@QueryParam("all") Boolean all) {
final Account account = optionalUserPrincipal(ctx);
@@ -900,7 +973,16 @@ public class AuthResource {
}

@POST @Path(EP_LOGOUT+"/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_AUTH},
summary="Logout a user everywhere",
description="Logout of the current session, or logout of all sessions everywhere if the `all` parameter is true.",
parameters={@Parameter(name="id", description="UUID or email of user to logout")},
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="If there is no current session to log out of")
}
)
public Response logoutUserEverywhere(@Context ContainerRequest ctx,
@PathParam("id") String id) {
final Account caller = optionalUserPrincipal(ctx);
@@ -916,11 +998,27 @@ public class AuthResource {
return ok_empty();
}

@GET @Path(EP_TIME) public Response serverTime() { return ok(now()); }
@GET @Path(EP_TIME)
@Operation(tags={API_TAG_UTILITY},
summary="Get current system time",
description="Get current system time. Returns current time as epoch time in milliseconds",
responses={
@ApiResponse(responseCode=SC_OK, description="Returns current time as epoch time in milliseconds",
content={@Content(mediaType=APPLICATION_JSON, examples={@ExampleObject(name="time in milliseconds", value="1606858589683")})})
}
)
public Response serverTime() { return ok(now()); }

@Autowired private GeoService geoService;

@GET @Path(EP_SUPPORT)
@Operation(tags={API_TAG_UTILITY},
summary="Get support information",
description="Get support information for the user's current locale, if available. Use the default locale otherwise.",
responses={
@ApiResponse(responseCode=SC_OK, description="SupportInfo object")
}
)
public Response getSupportInfo (@Context Request req,
@Context ContainerRequest ctx) {
final List<String> locales = geoService.getSupportedLocales(optionalUserPrincipal(ctx), getRemoteHost(req), normalizeLangHeader(req));
@@ -928,6 +1026,14 @@ public class AuthResource {
}

@GET @Path(EP_SUPPORT+"/{locale}")
@Operation(tags={API_TAG_UTILITY},
summary="Get support information",
description="Get support information for the given locale, if available. Use the default locale otherwise.",
parameters={@Parameter(name="locale", description="locale to find support for")},
responses={
@ApiResponse(responseCode=SC_OK, description="SupportInfo object")
}
)
public Response getSupportInfo (@Context Request req,
@Context ContainerRequest ctx,
@PathParam("locale") String locale) {
@@ -935,6 +1041,13 @@ public class AuthResource {
}

@GET @Path(EP_APP_LINKS)
@Operation(tags={API_TAG_UTILITY},
summary="Get links to native applications",
description="Get links to native applications for the current user's locale, if available. Use the default locale otherwise.",
responses={
@ApiResponse(responseCode=SC_OK, description="AppLinks object")
}
)
public Response getAppLinks (@Context Request req,
@Context ContainerRequest ctx) {
final List<String> locales = geoService.getSupportedLocales(optionalUserPrincipal(ctx), getRemoteHost(req), normalizeLangHeader(req));
@@ -942,6 +1055,14 @@ public class AuthResource {
}

@GET @Path(EP_APP_LINKS+"/{locale}")
@Operation(tags={API_TAG_UTILITY},
summary="Get links to native applications",
description="Get links to native applications for the given locale, if available. Use the default locale otherwise.",
parameters={@Parameter(name="locale", description="locale to find app links for")},
responses={
@ApiResponse(responseCode=SC_OK, description="AppLinks object")
}
)
public Response getAppLinks (@Context Request req,
@Context ContainerRequest ctx,
@PathParam("locale") String locale) {
@@ -950,6 +1071,15 @@ public class AuthResource {

@GET @Path(EP_PATCH+"/{token}")
@Produces(APPLICATION_OCTET_STREAM)
@Operation(tags={API_TAG_NODE_MANAGER},
summary="Find a node-manager patch file",
description="Find a node-manager patch file. The file must previously have been registered, yielding a token",
parameters={@Parameter(name="token", description="token of the patch file to retrieve")},
responses={
@ApiResponse(responseCode=SC_OK, description="raw file data", content={@Content(mediaType=APPLICATION_OCTET_STREAM)}),
@ApiResponse(responseCode=SC_NOT_FOUND, description="token not valid")
}
)
public Response getPatchFile(@Context ContainerRequest ctx,
@PathParam("token") String token) {
final File patch = nodeManagerService.findPatch(token);
@@ -961,6 +1091,19 @@ public class AuthResource {

@GET @Path(EP_UPGRADE+"/{node}/{key}")
@Produces(APPLICATION_OCTET_STREAM)
@Operation(tags={API_TAG_NODE},
summary="Return bubble jar",
description="Return bubble jar file for upgrading other nodes to our version.",
parameters={
@Parameter(name="node", description="UUID of the calling node"),
@Parameter(name="key", description="UUID of the calling node's BubbleNodeKey")
},
responses={
@ApiResponse(responseCode=SC_OK, description="raw jar file data", content={@Content(mediaType=APPLICATION_OCTET_STREAM)}),
@ApiResponse(responseCode=SC_UNAUTHORIZED, description="calling node is not authorized"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="token not valid")
}
)
public Response getUpgrade(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("node") String nodeUuid,


+ 0
- 18
bubble-server/src/main/java/bubble/server/BasicAppLinks.java Voir le fichier

@@ -1,18 +0,0 @@
/**
* Copyright (c) 2020 Bubble, Inc. All rights reserved.
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/
*/
package bubble.server;

import lombok.Getter;
import lombok.Setter;

public class BasicAppLinks {

@Getter @Setter private String ios;
@Getter @Setter private String android;
@Getter @Setter private String windows;
@Getter @Setter private String macosx;
@Getter @Setter private String linux;

}

+ 1
- 0
bubble-server/src/main/java/bubble/server/BubbleConfiguration.java Voir le fichier

@@ -13,6 +13,7 @@ import bubble.dao.account.AccountDAO;
import bubble.dao.bill.AccountPlanDAO;
import bubble.dao.bill.BubblePlanDAO;
import bubble.dao.cloud.CloudServiceDAO;
import bubble.model.AppLinks;
import bubble.model.bill.AccountPlan;
import bubble.model.bill.BubblePlan;
import bubble.model.cloud.BubbleNetwork;


+ 1
- 0
bubble-server/src/main/resources/bubble-config.yml Voir le fichier

@@ -17,6 +17,7 @@ openApi:
licenseUrl: https://getbubblenow.com/bubble-license/
additionalPackages:
- org.cobbzilla.wizard.model.search
- org.cobbzilla.wizard.model.support

defaultLocale: {{#exists BUBBLE_DEFAULT_LOCALE}}{{BUBBLE_DEFAULT_LOCALE}}{{else}}en_US{{/exists}}
testMode: {{#exists BUBBLE_TEST_MODE}}{{BUBBLE_TEST_MODE}}{{else}}false{{/exists}}


+ 1
- 1
utils/cobbzilla-wizard

@@ -1 +1 @@
Subproject commit c40f0704e1acb17ca3d1f1a4b590fe11997aa1b6
Subproject commit 09d23d287d18bfa2655f56cb80a3dd7c4bcc0816

Chargement…
Annuler
Enregistrer