/*
* Licensed under the Apache License, Version 2.0 (the "License");
*
* You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributions from 2013-2017 where performed either by US government
* employees, or under US Veterans Health Administration contracts.
*
* US Veterans Health Administration contributions by government employees
* are work of the U.S. Government and are not subject to copyright
* protection in the United States. Portions contributed by government
* employees are USGovWork (17USC ยง105). Not subject to copyright.
*
* Contribution by contractors to the US Veterans Health Administration
* during this period are contractually contributed under the
* Apache License, Version 2.0.
*
* See: https://www.usa.gov/government-works
*
* Contributions prior to 2013:
*
* Copyright (C) International Health Terminology Standards Development Organisation.
* Licensed under the Apache License, Version 2.0.
*
*/
package sh.isaac.provider.sync.git.gitblit.utils;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
//~--- non-JDK imports --------------------------------------------------------
import com.cedarsoftware.util.io.JsonObject;
import sh.isaac.provider.sync.git.gitblit.models.RepositoryModel;
//~--- classes ----------------------------------------------------------------
/**
* Utility methods for rpc calls.
*
*/
public class RpcUtils {
/** The Constant RPC_PATH. */
public static final String RPC_PATH = "/rpc/";
//~--- enums ---------------------------------------------------------------
/**
* The access permissions available for a repository.
*/
public static enum AccessPermission {
/** The none. */
NONE("N"),
/** The exclude. */
EXCLUDE("X"),
/** The view. */
VIEW("V"),
/** The clone. */
CLONE("R"),
/** The push. */
PUSH("RW"),
/** The create. */
CREATE("RWC"),
/** The delete. */
DELETE("RWD"),
/** The rewind. */
REWIND("RW+"),
/** The owner. */
OWNER("RW+");
/** The Constant NEWPERMISSIONS. */
public static final AccessPermission[] NEWPERMISSIONS = {
EXCLUDE, VIEW, CLONE, PUSH, CREATE, DELETE, REWIND
};
/** The Constant SSHPERMISSIONS. */
public static final AccessPermission[] SSHPERMISSIONS = { VIEW, CLONE, PUSH };
/** The legacy. */
public static AccessPermission LEGACY = REWIND;
//~--- fields -----------------------------------------------------------
/** The code. */
public final String code;
//~--- constructors -----------------------------------------------------
/**
* Instantiates a new access permission.
*
* @param code the code
*/
private AccessPermission(String code) {
this.code = code;
}
//~--- methods ----------------------------------------------------------
/**
* As role.
*
* @param repository the repository
* @return the string
*/
public String asRole(String repository) {
return this.code + ":" + repository;
}
/**
* At least.
*
* @param perm the perm
* @return true, if successful
*/
public boolean atLeast(AccessPermission perm) {
return ordinal() >= perm.ordinal();
}
/**
* At most.
*
* @param perm the perm
* @return true, if successful
*/
public boolean atMost(AccessPermission perm) {
return ordinal() <= perm.ordinal();
}
/**
* Exceeds.
*
* @param perm the perm
* @return true, if successful
*/
public boolean exceeds(AccessPermission perm) {
return ordinal() > perm.ordinal();
}
/**
* From code.
*
* @param code the code
* @return the access permission
*/
public static AccessPermission fromCode(String code) {
for (final AccessPermission perm: values()) {
if (perm.code.equalsIgnoreCase(code)) {
return perm;
}
}
return AccessPermission.NONE;
}
/**
* Permission from role.
*
* @param role the role
* @return the access permission
*/
public static AccessPermission permissionFromRole(String role) {
final String[] fields = role.split(":", 2);
if (fields.length == 1) {
// legacy/undefined assume full permissions
return AccessPermission.LEGACY;
} else {
// code:repository
return AccessPermission.fromCode(fields[0]);
}
}
/**
* Repository from role.
*
* @param role the role
* @return the string
*/
public static String repositoryFromRole(String role) {
final String[] fields = role.split(":", 2);
if (fields.length == 1) {
// legacy/undefined assume full permissions
return role;
} else {
// code:repository
return fields[1];
}
}
/**
* To string.
*
* @return the string
*/
@Override
public String toString() {
return this.code;
}
}
/**
* Enumeration representing the four access restriction levels.
*/
public static enum AccessRestrictionType {
/** The none. */
NONE,
/** The push. */
PUSH,
/** The clone. */
CLONE,
/** The view. */
VIEW;
/** The Constant AUTH_TYPES. */
private static final AccessRestrictionType[] AUTH_TYPES = { PUSH, CLONE, VIEW };
//~--- methods ----------------------------------------------------------
/**
* At least.
*
* @param type the type
* @return true, if successful
*/
public boolean atLeast(AccessRestrictionType type) {
return this.ordinal() >= type.ordinal();
}
/**
* Choices.
*
* @param allowAnonymousPush the allow anonymous push
* @return the list
*/
public static List<AccessRestrictionType> choices(boolean allowAnonymousPush) {
if (allowAnonymousPush) {
return Arrays.asList(values());
}
return Arrays.asList(AUTH_TYPES);
}
/**
* Exceeds.
*
* @param type the type
* @return true, if successful
*/
public boolean exceeds(AccessRestrictionType type) {
return this.ordinal() > type.ordinal();
}
/**
* From name.
*
* @param name the name
* @return the access restriction type
*/
public static AccessRestrictionType fromName(String name) {
for (final AccessRestrictionType type: values()) {
if (type.name()
.equalsIgnoreCase(name)) {
return type;
}
}
return NONE;
}
/**
* To string.
*
* @return the string
*/
@Override
public String toString() {
return name();
}
//~--- get methods ------------------------------------------------------
/**
* Checks if valid permission.
*
* @param permission the permission
* @return true, if valid permission
*/
public boolean isValidPermission(AccessPermission permission) {
switch (this) {
case VIEW:
// VIEW restriction
// all access permissions are valid
return true;
case CLONE:
// CLONE restriction
// only CLONE or greater access permissions are valid
return permission.atLeast(AccessPermission.CLONE);
case PUSH:
// PUSH restriction
// only PUSH or greater access permissions are valid
return permission.atLeast(AccessPermission.PUSH);
case NONE:
// NO access restriction
// all access permissions are invalid
return false;
}
return false;
}
}
/**
* Enumeration representing the types of authorization control for an
* access restricted resource.
*/
public static enum AuthorizationControl {
/** The authenticated. */
AUTHENTICATED,
/** The named. */
NAMED;
/**
* From name.
*
* @param name the name
* @return the authorization control
*/
public static AuthorizationControl fromName(String name) {
for (final AuthorizationControl type: values()) {
if (type.name()
.equalsIgnoreCase(name)) {
return type;
}
}
return NAMED;
}
/**
* To string.
*
* @return the string
*/
@Override
public String toString() {
return name();
}
}
/**
* Enumeration representing the federation types.
*/
public static enum FederationStrategy {
/** The exclude. */
EXCLUDE,
/** The federate this. */
FEDERATE_THIS,
/** The federate origin. */
FEDERATE_ORIGIN;
/**
* At least.
*
* @param type the type
* @return true, if successful
*/
public boolean atLeast(FederationStrategy type) {
return this.ordinal() >= type.ordinal();
}
/**
* Exceeds.
*
* @param type the type
* @return true, if successful
*/
public boolean exceeds(FederationStrategy type) {
return this.ordinal() > type.ordinal();
}
/**
* From name.
*
* @param name the name
* @return the federation strategy
*/
public static FederationStrategy fromName(String name) {
for (final FederationStrategy type: values()) {
if (type.name()
.equalsIgnoreCase(name)) {
return type;
}
}
return FEDERATE_THIS;
}
/**
* To string.
*
* @return the string
*/
@Override
public String toString() {
return name();
}
}
/**
* Enumeration representing the possible remote procedure call requests from
* a client.
*/
public static enum RpcRequest {
/** The create repository. */
CREATE_REPOSITORY,
/** The list repositories. */
LIST_REPOSITORIES;
/**
* Exceeds.
*
* @param type the type
* @return true, if successful
*/
public boolean exceeds(RpcRequest type) {
return this.ordinal() > type.ordinal();
}
/**
* From name.
*
* @param name the name
* @return the rpc request
*/
public static RpcRequest fromName(String name) {
for (final RpcRequest type: values()) {
if (type.name()
.equalsIgnoreCase(name)) {
return type;
}
}
return null;
}
/**
* To string.
*
* @return the string
*/
@Override
public String toString() {
return name();
}
}
//~--- methods -------------------------------------------------------------
/**
* As link.
*
* @param remoteURL the url of the remote gitblit instance
* @param req the rpc request type
* @param name the name of the actionable object
* @return the string
*/
public static String asLink(String remoteURL, RpcRequest req, String name) {
if ((remoteURL.length() > 0) && (remoteURL.charAt(remoteURL.length() - 1) == '/')) {
remoteURL = remoteURL.substring(0, remoteURL.length() - 1);
}
if (req == null) {
req = RpcRequest.LIST_REPOSITORIES;
}
return remoteURL + RPC_PATH + "?req=" + req.name().toLowerCase() + ((name == null) ? ""
: ("&name=" + StringUtils.encodeURL(name)));
}
/**
* Create a repository on the Gitblit server.
*
* @param repository the repository
* @param serverUrl the server url
* @param account the account
* @param password the password
* @return true if the action succeeded
* @throws IOException Signals that an I/O exception has occurred.
*/
public static boolean createRepository(RepositoryModel repository,
String serverUrl,
String account,
char[] password)
throws IOException {
// ensure repository name ends with .git
if (!repository.name.endsWith(".git")) {
repository.name += ".git";
}
return doAction(RpcRequest.CREATE_REPOSITORY, null, repository, serverUrl, account, password);
}
/**
* Do the specified administrative action on the Gitblit server.
*
* @param request the request
* @param name the name of the object (may be null)
* @param object the object
* @param serverUrl the server url
* @param account the account
* @param password the password
* @return true if the action succeeded
* @throws IOException Signals that an I/O exception has occurred.
*/
protected static boolean doAction(RpcRequest request,
String name,
Object object,
String serverUrl,
String account,
char[] password)
throws IOException {
final String url = asLink(serverUrl, request, name);
final int resultCode = JsonUtils.sendJsonString(url, JsonUtils.toJsonString(object), account, password);
return resultCode == 200;
}
//~--- get methods ---------------------------------------------------------
/**
* Retrieves a map of the repositories at the remote gitblit instance keyed
* by the repository clone url.
*
* @param serverUrl the server url
* @param account the account
* @param password the password
* @return a map of cloneable repositories
* @throws IOException Signals that an I/O exception has occurred.
*/
public static JsonObject<String, Map<String, ?>> getRepositories(String serverUrl,
String account,
char[] password)
throws IOException {
final String url = asLink(serverUrl, RpcRequest.LIST_REPOSITORIES, null);
return JsonUtils.retrieveJson(url, account, password);
}
}