Moved swt gradle script to a better location (inside scripts dir). Added ext.swt customization
This commit is contained in:
parent
c832edc3a0
commit
ad94bfddf1
@ -1,4 +1,13 @@
|
||||
String getSWTWindowingLibrary() {
|
||||
if (ext.has('swt')) {
|
||||
switch (ext.swt) {
|
||||
case ~/.*linux.*/: return 'gtk'
|
||||
case ~/.*mac.*/: return 'cocoa'
|
||||
case ~/.*win.*/: return 'win32'
|
||||
default: return null
|
||||
}
|
||||
}
|
||||
|
||||
String platform = System.properties['os.name']
|
||||
|
||||
switch (platform.replaceAll(' ', '').toLowerCase()) {
|
||||
@ -13,6 +22,10 @@ String getSWTWindowingLibrary() {
|
||||
String getSWTArch() {
|
||||
String arch = System.properties['os.arch']
|
||||
|
||||
if (ext.has('swt')) {
|
||||
arch = ext.swt
|
||||
}
|
||||
|
||||
switch (arch) {
|
||||
case ~/.*64.*/: return 'x86_64'
|
||||
default: return 'x86'
|
||||
@ -20,6 +33,15 @@ String getSWTArch() {
|
||||
}
|
||||
|
||||
String getSWTPlatform() {
|
||||
if (ext.has('swt')) {
|
||||
switch (ext.swt) {
|
||||
case ~/.*linux.*/: return 'linux'
|
||||
case ~/.*mac.*/: return 'macosx'
|
||||
case ~/.*win.*/: return 'win32'
|
||||
default: return null
|
||||
}
|
||||
}
|
||||
|
||||
String platform = System.properties['os.name']
|
||||
|
||||
switch (platform.replaceAll(' ', '').toLowerCase()) {
|
||||
@ -31,6 +53,9 @@ String getSWTPlatform() {
|
||||
}
|
||||
}
|
||||
|
||||
// optionally let us specify which SWT to use. options are win32/mac32/linux32 and win64/mac64/linux64
|
||||
// include this in your build.gradle file, before dependencies are determined. ext.swt = 'win64'
|
||||
|
||||
ext {
|
||||
// because the eclipse release of SWT is abandoned on maven, this MAVEN repo has newer version of SWT,
|
||||
// https://github.com/maven-eclipse/maven-eclipse.github.io (for the website about it)
|
@ -15,8 +15,11 @@
|
||||
*/
|
||||
package dorkbox.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
/** A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance
|
||||
* with RFC 2045.<br><br>
|
||||
* On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is about 10 times faster
|
||||
@ -25,7 +28,7 @@ import java.util.Arrays;
|
||||
*
|
||||
* On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 Codec for encode and
|
||||
* about 50% faster for decoding large arrays. This implementation is about twice as fast on very small
|
||||
* arrays (< 30 bytes). If source/destination is a <code>String</code> this
|
||||
* arrays (< 30 bytes). If source/destination is a <code>String</code> this
|
||||
* version is about three times as fast due to the fact that the Commons Codec result has to be recoded
|
||||
* to a <code>String</code> from <code>byte[]</code>, which is very expensive.<br><br>
|
||||
*
|
||||
@ -97,6 +100,50 @@ public class Base64Fast
|
||||
IA['='] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats data into a nicely formatted base64 encoded String
|
||||
*
|
||||
* @param s A string containing the base64 encoded data
|
||||
* @param lineLength The number of characters per line
|
||||
* @param prefix A string prefixing the characters on each line
|
||||
* @param addClose Whether to add a close parenthesis or not
|
||||
*
|
||||
* @return A String representing the formatted output
|
||||
*/
|
||||
public static
|
||||
String formatString(String s, int lineLength, String prefix, boolean addClose) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < s.length(); i += lineLength) {
|
||||
sb.append(prefix);
|
||||
if (i + lineLength >= s.length()) {
|
||||
sb.append(s.substring(i));
|
||||
if (addClose) {
|
||||
sb.append(" )");
|
||||
}
|
||||
}
|
||||
else {
|
||||
sb.append(s.substring(i, i + lineLength));
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static
|
||||
String encode2(byte[] data) {
|
||||
// will skip/ignore invalid chars!
|
||||
return DatatypeConverter.printBase64Binary(data);
|
||||
}
|
||||
|
||||
public static
|
||||
byte[] decode2(String base64) throws IOException {
|
||||
// this is the fastest way to do string->byte conversion
|
||||
// http://java-performance.info/base64-encoding-and-decoding-performance/
|
||||
// will skip/ignore invalid chars!
|
||||
return DatatypeConverter.parseBase64Binary(base64);
|
||||
}
|
||||
|
||||
|
||||
// ****************************************************************************************
|
||||
// * char[] version
|
||||
// ****************************************************************************************
|
||||
|
@ -1,490 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 dorkbox, llc
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package dorkbox.util;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Version a = new Version("1.1");
|
||||
* Version b = new Version("1.1.1");
|
||||
* a.compareTo(b) // return -1 (a<b)
|
||||
* a.equals(b) // return false
|
||||
* <p>
|
||||
* Version a = new Version("2.0");
|
||||
* Version b = new Version("1.9.9");
|
||||
* a.compareTo(b) // return 1 (a>b)
|
||||
* a.equals(b) // return false
|
||||
* <p>
|
||||
* Version a = new Version("1.0");
|
||||
* Version b = new Version("1");
|
||||
* a.compareTo(b) // return 0 (a=b)
|
||||
* a.equals(b) // return true
|
||||
* <p>
|
||||
* Version a = new Version("1");
|
||||
* Version b = null;
|
||||
* a.compareTo(b) // return 1 (a>b)
|
||||
* a.equals(b) // return false
|
||||
* <p>
|
||||
* List<Version> versions = new ArrayList<Version>();
|
||||
* versions.add(new Version("2"));
|
||||
* versions.add(new Version("1.0.5"));
|
||||
* versions.add(new Version("1.01.0"));
|
||||
* versions.add(new Version("1.00.1"));
|
||||
* Collections.min(versions).get() // return min version
|
||||
* Collections.max(versions).get() // return max version
|
||||
* <p>
|
||||
* // WARNING
|
||||
* Version a = new Version("2.06");
|
||||
* Version b = new Version("2.060");
|
||||
* a.equals(b) // return false
|
||||
* <p>
|
||||
* <p>
|
||||
* If the numbers are the same, then
|
||||
* BETA+BUILD < BETA < STABLE+BUILD < STABLE.
|
||||
* <p>
|
||||
* Stable is a version that is exclusively numbers. Builds are always equal, even if a different build commit hash/etc.
|
||||
*/
|
||||
@SuppressWarnings({"unused", "SimplifiableIfStatement", "WeakerAccess"})
|
||||
public
|
||||
class Version implements Comparable<Version> {
|
||||
private static final int[] PRIME = {2, 3, 5};
|
||||
|
||||
// protected scope to permit overriding functionality
|
||||
|
||||
protected String version;
|
||||
protected int[] internalVersion;
|
||||
|
||||
protected boolean isBeta;
|
||||
protected String build;
|
||||
|
||||
protected
|
||||
Version() {
|
||||
// no-arg for serialization
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comparable version based on only numbers
|
||||
*
|
||||
* @param version must consist of just numbers with a maximum of 1 decimal point
|
||||
*/
|
||||
public
|
||||
Version(double version) {
|
||||
this(Double.toString(version), false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comparable version from a string
|
||||
*
|
||||
* @param version The version part must consist of just numbers with a maximum of 3 groups separated by a '.' and BETA or BUILD info
|
||||
*/
|
||||
public
|
||||
Version(String version) {
|
||||
this(Version.fromString(version));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comparable version based on an existing version
|
||||
*/
|
||||
public
|
||||
Version(final Version version) {
|
||||
this.version = version.version;
|
||||
this.internalVersion = version.internalVersion;
|
||||
this.isBeta = version.isBeta;
|
||||
this.build = version.build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comparable version based on numbers, BETA status, and BUILD
|
||||
*
|
||||
* @param version must consist of only numbers with a maximum of 3 groups separated by a '.' Leading '0' will be removed
|
||||
* @param isBeta true if this is a beta build
|
||||
* @param build custom build info, such as the commit sha hash
|
||||
*/
|
||||
public
|
||||
Version(String version, boolean isBeta, String build) {
|
||||
if (version == null) {
|
||||
throw new IllegalArgumentException("Version can not be null");
|
||||
}
|
||||
if (!version.matches("[0-9]+(\\.[0-9]+){0,3}")) {
|
||||
throw new IllegalArgumentException("Invalid version format");
|
||||
}
|
||||
|
||||
if (build != null) {
|
||||
this.build = build.toLowerCase(Locale.US);
|
||||
}
|
||||
else {
|
||||
this.build = null;
|
||||
}
|
||||
|
||||
this.isBeta = isBeta;
|
||||
this.version = version;
|
||||
|
||||
String[] parts = this.version.split("\\.");
|
||||
internalVersion = new int[parts.length];
|
||||
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
final String s = parts[i];
|
||||
internalVersion[i] = Integer.parseInt(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comparable version based on only numbers
|
||||
*/
|
||||
public
|
||||
Version(String... version) {
|
||||
if (version == null) {
|
||||
throw new IllegalArgumentException("Version can not be null");
|
||||
}
|
||||
|
||||
int length = version.length;
|
||||
if (length > 3) {
|
||||
throw new IllegalArgumentException("Invalid version format");
|
||||
}
|
||||
|
||||
this.build = null;
|
||||
this.isBeta = false;
|
||||
|
||||
StringBuilder builder = new StringBuilder(length + 3);
|
||||
internalVersion = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
final String s = version[i];
|
||||
// must be a number
|
||||
internalVersion[i] = Integer.parseInt(s);
|
||||
builder.append(s)
|
||||
.append('.');
|
||||
}
|
||||
|
||||
this.version = builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comparable version based on only numbers
|
||||
*/
|
||||
public
|
||||
Version(int... version) {
|
||||
if (version == null) {
|
||||
throw new IllegalArgumentException("Version can not be null");
|
||||
}
|
||||
|
||||
if (version.length > 3) {
|
||||
throw new IllegalArgumentException("Invalid version format");
|
||||
}
|
||||
|
||||
this.build = null;
|
||||
this.isBeta = false;
|
||||
|
||||
StringBuilder builder = new StringBuilder(version.length + 3);
|
||||
internalVersion = new int[version.length];
|
||||
for (int i = 0; i < version.length; i++) {
|
||||
internalVersion[i] = version[i];
|
||||
builder.append(i)
|
||||
.append('.');
|
||||
}
|
||||
|
||||
this.version = builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a version into a "beta" version, without any additional build information
|
||||
* <p>
|
||||
* BETA+BUILD < BETA < STABLE+BUILD < STABLE.
|
||||
* Stable is a version that is exclusively numbers. Builds are always equal, even if a different build commit hash/etc.
|
||||
*/
|
||||
public
|
||||
Version beta() {
|
||||
this.isBeta = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a version with specific build information (such as sha commit hash, etc)
|
||||
* <p>
|
||||
* BETA+BUILD < BETA < STABLE+BUILD < STABLE.
|
||||
* Stable is a version that is exclusively numbers. Builds are always equal, even if a different build commit hash/etc.
|
||||
*/
|
||||
public
|
||||
Version build(String build) {
|
||||
this.build = build;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the version information, as an array.
|
||||
*/
|
||||
public
|
||||
int[] getVersion() {
|
||||
return internalVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this version is a beta or not
|
||||
*/
|
||||
public
|
||||
boolean isBeta() {
|
||||
return isBeta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the build information, if any
|
||||
*/
|
||||
public
|
||||
String getBuild() {
|
||||
return build;
|
||||
}
|
||||
|
||||
public
|
||||
boolean isGreater(Object that) {
|
||||
if (this == that) {
|
||||
return false;
|
||||
}
|
||||
if (that == null) {
|
||||
return true;
|
||||
}
|
||||
if (this.getClass() != that.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.compareTo((Version) that) > 0;
|
||||
}
|
||||
|
||||
public
|
||||
boolean isGreaterOrEquals(Object that) {
|
||||
if (this == that) {
|
||||
return true;
|
||||
}
|
||||
if (that == null) {
|
||||
return true;
|
||||
}
|
||||
if (this.getClass() != that.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.compareTo((Version) that) >= 0;
|
||||
}
|
||||
|
||||
public
|
||||
boolean isLess(Object that) {
|
||||
if (this == that) {
|
||||
return false;
|
||||
}
|
||||
if (that == null) {
|
||||
return false;
|
||||
}
|
||||
if (this.getClass() != that.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.compareTo((Version) that) < 0;
|
||||
}
|
||||
|
||||
public
|
||||
boolean isLessOrEquals(Object that) {
|
||||
if (this == that) {
|
||||
return true;
|
||||
}
|
||||
if (that == null) {
|
||||
return false;
|
||||
}
|
||||
if (this.getClass() != that.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.compareTo((Version) that) <= 0;
|
||||
}
|
||||
|
||||
public
|
||||
boolean isEquals(Object that) {
|
||||
return equals(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
boolean equals(Object that) {
|
||||
if (this == that) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (that == null) {
|
||||
return false;
|
||||
}
|
||||
if (this.getClass() != that.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.compareTo((Version) that) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
int compareTo(Version that) {
|
||||
if (that == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int[] thisParts = this.internalVersion;
|
||||
int[] thatParts = that.internalVersion;
|
||||
|
||||
int maxLength = Math.max(thisParts.length, thatParts.length);
|
||||
|
||||
for (int i = 0; i < maxLength; i++) {
|
||||
int thisPart;
|
||||
if (i < thisParts.length) {
|
||||
thisPart = thisParts[i];
|
||||
}
|
||||
else {
|
||||
thisPart = 0;
|
||||
}
|
||||
|
||||
int thatPart;
|
||||
if (i < thatParts.length) {
|
||||
thatPart = thatParts[i];
|
||||
}
|
||||
else {
|
||||
thatPart = 0;
|
||||
}
|
||||
|
||||
if (thisPart < thatPart) {
|
||||
return -1;
|
||||
}
|
||||
if (thisPart > thatPart) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// our numbers are all equal, now determine equality based on BETA/BUILD info
|
||||
|
||||
// BETA+BUILD < BETA < STABLE+BUILD < STABLE.
|
||||
// Stable is a version that is exclusively numbers. Builds are always equal, even if a different build commit hash/etc.
|
||||
|
||||
if (this.isBeta) {
|
||||
if (this.build != null) {
|
||||
if (that.isBeta) {
|
||||
if (that.build != null) {
|
||||
// BETA+BUILD == BETA+BUILD
|
||||
return 0;
|
||||
}
|
||||
// BETA+BUILD < BETA
|
||||
return -1;
|
||||
}
|
||||
// BETA+BUILD < STABLE+BUILD < STABLE
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (that.isBeta) {
|
||||
if (that.build != null) {
|
||||
// BETA > BETA+BUILD
|
||||
return 1;
|
||||
}
|
||||
// BETA == BETA
|
||||
return 0;
|
||||
}
|
||||
// BETA < STABLE+BUILD < STABLE
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// else this is STABLE or STABLE+BUILD
|
||||
|
||||
if (this.build != null) {
|
||||
if (that.isBeta) {
|
||||
// STABLE+BUILD > BETA > BETA+BUILD
|
||||
return 1;
|
||||
}
|
||||
if (that.build != null) {
|
||||
// STABLE+BUILD == STABLE+BUILD
|
||||
return 0;
|
||||
}
|
||||
// STABLE+BUILD < STABLE
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (that.isBeta) {
|
||||
// STABLE > BETA > BETA+BUILD
|
||||
return 1;
|
||||
}
|
||||
if (that.build != null) {
|
||||
// STABLE > STABLE+BUILD
|
||||
return 1;
|
||||
}
|
||||
// STABLE == STABLE
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final
|
||||
int hashCode() {
|
||||
// better hashing than just using .toString().hashCode()
|
||||
int hashCode = 0;
|
||||
for (int i = 0; i < internalVersion.length; i++) {
|
||||
final int part = internalVersion[i];
|
||||
if (part > 0) {
|
||||
hashCode += PRIME[i] ^ part;
|
||||
}
|
||||
}
|
||||
|
||||
if (build != null) {
|
||||
hashCode += build.hashCode();
|
||||
}
|
||||
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts version information from a string
|
||||
*
|
||||
* @param string The version string, as received by {@link Version#toString()}
|
||||
*/
|
||||
public static
|
||||
Version fromString(String string) {
|
||||
int betaIndex = string.indexOf("-BETA");
|
||||
int buildIndex = string.indexOf("+");
|
||||
int lastIndex = string.length();
|
||||
|
||||
|
||||
boolean isBeta = betaIndex > 0;
|
||||
String build = null;
|
||||
if (buildIndex > 0) {
|
||||
build = string.substring(buildIndex + 1, lastIndex);
|
||||
lastIndex = buildIndex;
|
||||
}
|
||||
|
||||
if (isBeta) {
|
||||
lastIndex = betaIndex;
|
||||
}
|
||||
|
||||
String version = string.substring(0, lastIndex);
|
||||
|
||||
return new Version(version, isBeta, build);
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
String toString() {
|
||||
if (isBeta) {
|
||||
if (build != null) {
|
||||
return version + "-BETA+" + build;
|
||||
}
|
||||
return version + "-BETA";
|
||||
}
|
||||
if (build != null) {
|
||||
return version + "+" + build;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
}
|
110
src/dorkbox/util/userManagement/Group.java
Normal file
110
src/dorkbox/util/userManagement/Group.java
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2018 dorkbox, llc
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package dorkbox.util.userManagement;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
// TODO: this class needs to save itself to the database on changes
|
||||
/**
|
||||
* Plugable group object for user management
|
||||
*/
|
||||
public final
|
||||
class Group implements Serializable {
|
||||
|
||||
private final UUID uuid;
|
||||
private String name;
|
||||
|
||||
private Set<UUID> users = new HashSet<UUID>();
|
||||
|
||||
public
|
||||
Group(final String name) {
|
||||
this(name, UserManagement.UUID_GENERATOR.generate());
|
||||
}
|
||||
|
||||
Group(final String name, final UUID uuid) {
|
||||
this.name = name;
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public
|
||||
UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public synchronized
|
||||
void addUser(UUID user) {
|
||||
users.add(user);
|
||||
}
|
||||
|
||||
public synchronized
|
||||
void removeUser(UUID user) {
|
||||
users.remove(user);
|
||||
}
|
||||
|
||||
public synchronized
|
||||
Collection<UUID> getUsers() {
|
||||
return Collections.unmodifiableCollection(users);
|
||||
}
|
||||
|
||||
public synchronized
|
||||
boolean isEmpty() {
|
||||
return users.isEmpty();
|
||||
}
|
||||
|
||||
public synchronized
|
||||
void remove() {
|
||||
// UserManagement.Groups.remove(this);
|
||||
|
||||
// for (User user : users) {
|
||||
// user.removeGroup(this);
|
||||
// }
|
||||
|
||||
users.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
String toString() {
|
||||
return "Group '" + name + '\'';
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Group group = (Group) o;
|
||||
|
||||
return uuid != null ? uuid.equals(group.uuid) : group.uuid == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
int hashCode() {
|
||||
return uuid != null ? uuid.hashCode() : 0;
|
||||
}
|
||||
}
|
123
src/dorkbox/util/userManagement/User.java
Normal file
123
src/dorkbox/util/userManagement/User.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2018 dorkbox, llc
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package dorkbox.util.userManagement;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
// TODO: this class needs to save itself to the database on changes
|
||||
|
||||
|
||||
public
|
||||
class User implements Serializable {
|
||||
/** Global, unique ID for this user. This is the only thing used to determine equality */
|
||||
private final UUID uuid;
|
||||
|
||||
/** Random, per-user salt that is used for secure password hashing */
|
||||
private final byte[] salt = new byte[256];
|
||||
|
||||
/** user name assigned. Equality is determined by the UUID, so depending on use, the name does not have to be unique. */
|
||||
protected String name;
|
||||
|
||||
/** This is the groups that this user is a member of */
|
||||
private final Set<UUID> groups = new HashSet<UUID>();
|
||||
|
||||
public
|
||||
User() {
|
||||
uuid = UserManagement.UUID_GENERATOR.generate();
|
||||
UserManagement.RANDOM.nextBytes(salt);
|
||||
}
|
||||
|
||||
User(final UUID uuid, final byte[] salt) {
|
||||
this.uuid = uuid;
|
||||
|
||||
// set the salt
|
||||
for (int i = 0, saltLength = salt.length; i < saltLength; i++) {
|
||||
this.salt[i] = salt[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the global, unique ID for this user. This is the only thing used to determine equality
|
||||
*/
|
||||
public final
|
||||
UUID getUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a random, per-user salt that is used for secure password hashing
|
||||
*/
|
||||
public final
|
||||
byte[] getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an unmodifiable set of groups this user is a member of
|
||||
*/
|
||||
public final
|
||||
Set<UUID> getGroups() {
|
||||
return Collections.unmodifiableSet(groups);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the user name assigned. Equality is determined by the UUID, so depending on use, the name does not have to be unique.
|
||||
*/
|
||||
public final
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the user name to be assigned. Equality is determined by the UUID, so depending on use, the name does not have to be unique.
|
||||
*/
|
||||
public final
|
||||
void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final User user = (User) o;
|
||||
|
||||
return uuid.equals(user.uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
int hashCode() {
|
||||
return uuid.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
String toString() {
|
||||
return "User {" + uuid + ", '" + name + '\'' + '}';
|
||||
}
|
||||
}
|
424
src/dorkbox/util/userManagement/UserManagement.java
Normal file
424
src/dorkbox/util/userManagement/UserManagement.java
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright 2018 dorkbox, llc
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package dorkbox.util.userManagement;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.uuid.Generators;
|
||||
import com.fasterxml.uuid.impl.RandomBasedGenerator;
|
||||
import com.fasterxml.uuid.impl.UUIDUtil;
|
||||
|
||||
/**
|
||||
* todo: this class should load/save itself to the database
|
||||
*/
|
||||
public final
|
||||
class UserManagement {
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserManagement.class.getSimpleName());
|
||||
|
||||
static final RandomBasedGenerator UUID_GENERATOR = Generators.randomBasedGenerator();
|
||||
static final SecureRandom RANDOM = new SecureRandom();
|
||||
|
||||
public final Group ADMIN;
|
||||
|
||||
private Map<UUID, User> users = new HashMap<UUID, User>();
|
||||
private Map<UUID, Group> groups = new HashMap<UUID, Group>();
|
||||
|
||||
public
|
||||
UserManagement() {
|
||||
// the "system/admin/root" group MUST always be all "0"
|
||||
final byte[] buffer = new byte[16];
|
||||
for (int i = 0, bufferLength = buffer.length; i < bufferLength; i++) {
|
||||
buffer[i] = 0;
|
||||
}
|
||||
|
||||
UUID uuid = UUIDUtil.uuid(buffer);
|
||||
ADMIN = new Group("System", uuid);
|
||||
|
||||
// the "system/root" group MUST always be all "0"
|
||||
groups.put(uuid, ADMIN);
|
||||
}
|
||||
|
||||
public
|
||||
User authenticate(String user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// public
|
||||
// byte[] generateUserNameHash(String username) {
|
||||
// return HashUtil.getSha256WithSalt(username, getSalt());
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////
|
||||
/// user/group create/add/remove/get actions
|
||||
/////////////////
|
||||
|
||||
public
|
||||
User createUser() {
|
||||
User user = new User();
|
||||
addUser(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
private
|
||||
void addUser(User user) {
|
||||
// users.add(user);
|
||||
}
|
||||
|
||||
private
|
||||
void removeUser(User user) {
|
||||
users.remove(user);
|
||||
}
|
||||
|
||||
public
|
||||
Map<UUID, User> getUsers() {
|
||||
return Collections.unmodifiableMap(users);
|
||||
}
|
||||
|
||||
public
|
||||
User getUser(final UUID uuid) {
|
||||
return users.get(uuid);
|
||||
}
|
||||
|
||||
public
|
||||
Group createGroup(String groupName) {
|
||||
Group group = new Group(groupName);
|
||||
addGroup(group);
|
||||
return group;
|
||||
}
|
||||
|
||||
public
|
||||
void addGroup(final Group group) {
|
||||
// groups.add(group);
|
||||
}
|
||||
|
||||
public
|
||||
void removeGroup(final Group group) {
|
||||
if (group != ADMIN) {
|
||||
groups.remove(group);
|
||||
}
|
||||
}
|
||||
|
||||
// public
|
||||
// Collection<Group> getGroups() {
|
||||
// return Collections.unmodifiableCollection(groups);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @param user the user to check
|
||||
// * @return true if this user is in the admin group
|
||||
// */
|
||||
// public
|
||||
// boolean isAdminGroup(final User user) {
|
||||
// return ADMIN.getUsers()
|
||||
// .contains(user.getUUID());
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * check if a user is the admin user
|
||||
// *
|
||||
// * @return false if not admin, or NOT called from the console
|
||||
// */
|
||||
// public synchronized
|
||||
// boolean isAdminUser(final byte[] userNameHash) {
|
||||
// if (userNameHash == null || userNameHash.length == 0) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// if (!checkAccessNoExit(SystemLoginImpl.class, AdminActions.class, ConsoleServer.class)) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// if (adminUserHash == null) {
|
||||
// Exit.FailedConfiguration("Unable to read admin user from the database. FORCED SHUTDOWN.");
|
||||
// return false;
|
||||
// }
|
||||
// else {
|
||||
// if (Arrays.equals(adminUserHash, userNameHash)) {
|
||||
// return true;
|
||||
// }
|
||||
// else {
|
||||
// AdminActions.this.logger.info("User is not the admin user");
|
||||
// return false; // user not the same
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Set's the admin user for this server. This user should already exist!
|
||||
// *
|
||||
// * @return errormessage, if there are errors, null otherwise
|
||||
// */
|
||||
// public synchronized
|
||||
// String setAdminUser(final byte[] userNameHash, final byte[] currentAdminPasswordHash) {
|
||||
// try {
|
||||
// checkAccess(AdminActions.class, ConsoleServer.class);
|
||||
// } catch (SecurityException e) {
|
||||
// Exit.FailedSecurity(e);
|
||||
// }
|
||||
//
|
||||
// // only check the password if we have an admin user!
|
||||
// if (adminUserHash != null) {
|
||||
// final ByteArrayWrapper adminUserHashWrap = ByteArrayWrapper.wrap(adminUserHash);
|
||||
// DB_User user = users.get(adminUserHashWrap);
|
||||
// if (user != null) {
|
||||
// if (!Arrays.equals(user.getPasswordHash(), currentAdminPasswordHash)) {
|
||||
// String mesg = "Incorrect admin password.";
|
||||
// AdminActions.this.logger.info(mesg);
|
||||
// return mesg;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// String mesg = "Invalid user!";
|
||||
// AdminActions.this.logger.info(mesg);
|
||||
// return mesg;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// final ByteArrayWrapper userHashWrap = ByteArrayWrapper.wrap(userNameHash);
|
||||
// DB_User user = users.get(userHashWrap);
|
||||
// if (user == null) {
|
||||
// String mesg = "User doesn't exist.";
|
||||
// AdminActions.this.logger.info(mesg);
|
||||
// return mesg;
|
||||
// }
|
||||
//
|
||||
// adminUserHash = userNameHash;
|
||||
//
|
||||
// // have to always specify what we are saving
|
||||
// storage.put(DatabaseStorage.ADMIN_HASH, adminUserHash);
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Adds a user to the system. beware userName != usernamehash
|
||||
// *
|
||||
// * @return the error message, null if successful.
|
||||
// */
|
||||
// public synchronized
|
||||
// String addUser(final String userName, final byte[] userNameHash, final byte[] passwordHash) {
|
||||
// try {
|
||||
// checkAccess(AdminActions.class, ConsoleServer.class);
|
||||
// } catch (SecurityException e) {
|
||||
// Exit.FailedSecurity(e);
|
||||
// }
|
||||
//
|
||||
// String validateLogin = Validation.userName(userName);
|
||||
// Logger logger2 = this.logger;
|
||||
// if (validateLogin != null) {
|
||||
// String mesg = "Unable to create user account ( " + userName + " ). Reason: " + validateLogin;
|
||||
// if (logger2.isInfoEnabled()) {
|
||||
// logger2.info("{} Reason: {}", mesg, validateLogin);
|
||||
// }
|
||||
// return mesg;
|
||||
// }
|
||||
//
|
||||
// final ByteArrayWrapper userNameHashWrap = ByteArrayWrapper.wrap(userNameHash);
|
||||
//
|
||||
// // only once, to save memory
|
||||
// DB_User user = users.get(userNameHashWrap);
|
||||
//
|
||||
// if (user != null) {
|
||||
// String mesg = "Unable to create user account ( " + userName + " ). Reason: User already exists";
|
||||
// if (logger2.isInfoEnabled()) {
|
||||
// logger2.info(mesg);
|
||||
// }
|
||||
// return mesg;
|
||||
// }
|
||||
// else {
|
||||
// user = new DB_User();
|
||||
// user.setName(userName);
|
||||
// user.setNameHash(userNameHash);
|
||||
// user.setPasswordHash(passwordHash);
|
||||
//
|
||||
// users.put(userNameHashWrap, user);
|
||||
// // have to always specify what we are saving
|
||||
// storage.put(DatabaseStorage.USERS, users);
|
||||
//
|
||||
// if (logger2.isInfoEnabled()) {
|
||||
// logger2.info("Added user ({})", userName);
|
||||
// }
|
||||
// return null; // success!
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * remove a user + userName hash.
|
||||
// *
|
||||
// * @return true if removed, false if the user could not be removed.
|
||||
// */
|
||||
// public synchronized
|
||||
// boolean removeUser(final byte[] userNameHash) {
|
||||
// final ByteArrayWrapper userNameHashWrap = ByteArrayWrapper.wrap(userNameHash);
|
||||
// DB_User user = users.get(userNameHashWrap);
|
||||
//
|
||||
// Logger logger2 = this.logger;
|
||||
// if (user != null) {
|
||||
// byte[] userNameCheck = user.getNameHash();
|
||||
// if (Arrays.equals(userNameHash, userNameCheck) && !isAdminUser(userNameHash)) {
|
||||
//
|
||||
// DB_User removedUser = users.remove(userNameHashWrap);
|
||||
// String name = user.getName();
|
||||
//
|
||||
// if (removedUser != null) {
|
||||
// // have to always specify what we are saving
|
||||
// storage.put(DatabaseStorage.USERS, users);
|
||||
// return true;
|
||||
// }
|
||||
// else {
|
||||
// if (logger2.isInfoEnabled()) {
|
||||
// logger2.info("Problem removing the user ({}). Does not exist.", name);
|
||||
// }
|
||||
// return false; // problem removing the user
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (logger2.isInfoEnabled()) {
|
||||
// logger2.info("Problem removing unknown user");
|
||||
// }
|
||||
// return false; // problem removing the user
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Force set the password for a user in the system.
|
||||
// *
|
||||
// * @return the error message, null if successful.
|
||||
// */
|
||||
// public synchronized
|
||||
// String setPasswordUser(final byte[] userNameHash, final byte[] passwordHash, final byte[] adminPasswordHash) {
|
||||
// try {
|
||||
// checkAccess(ConsoleServer.class);
|
||||
// } catch (SecurityException e) {
|
||||
// Exit.FailedSecurity(e);
|
||||
// }
|
||||
//
|
||||
// final ByteArrayWrapper adminUserHashWrap = ByteArrayWrapper.wrap(adminPasswordHash);
|
||||
// DB_User adminUser = users.get(adminUserHashWrap);
|
||||
//
|
||||
// Logger logger2 = this.logger;
|
||||
// if (adminUser == null || !Arrays.equals(adminUser.getPasswordHash(), adminPasswordHash)) {
|
||||
// String mesg = "Unable to authenticate admin password.";
|
||||
// if (logger2.isInfoEnabled()) {
|
||||
// logger2.info(mesg);
|
||||
// }
|
||||
// return mesg;
|
||||
// }
|
||||
//
|
||||
// final ByteArrayWrapper userNameHashWrap = ByteArrayWrapper.wrap(userNameHash);
|
||||
// DB_User user = users.get(userNameHashWrap);
|
||||
// if (user != null) {
|
||||
// user.setPasswordHash(passwordHash);
|
||||
// // have to always specify what we are saving
|
||||
// storage.put(DatabaseStorage.USERS, users);
|
||||
//
|
||||
// String name = user.getName();
|
||||
// if (logger2.isInfoEnabled()) {
|
||||
// logger2.info("Reset password for user ({})", name);
|
||||
// }
|
||||
// return null; // success!
|
||||
// }
|
||||
// else {
|
||||
// String mesg = "Unable to change the password for non-existant user.";
|
||||
// if (logger2.isInfoEnabled()) {
|
||||
// logger2.info(mesg);
|
||||
// }
|
||||
// return mesg;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * faster check that userExists(), as it only check the hash
|
||||
// */
|
||||
// public synchronized
|
||||
// User getUser(final byte[] usernameHash) {
|
||||
// if (usernameHash == null) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// checkAccess(SystemLoginImpl.class, AdminActions.class, ConsoleServer.class);
|
||||
// } catch (SecurityException e) {
|
||||
// Exit.FailedSecurity(e);
|
||||
// }
|
||||
//
|
||||
// return users.get(ByteArrayWrapper.wrap(usernameHash));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * gets the user password given the userName hash
|
||||
// *
|
||||
// * @return NON NULL VALUE
|
||||
// */
|
||||
// public synchronized
|
||||
// byte[] getPasswordHash(final byte[] userNameHash) {
|
||||
// if (userNameHash == null || userNameHash.length == 0) {
|
||||
// return new byte[0];
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// checkAccess(AdminActions.class);
|
||||
// } catch (SecurityException e) {
|
||||
// Exit.FailedSecurity(e);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// DB_User user = users.get(ByteArrayWrapper.wrap(userNameHash));
|
||||
// if (user != null) {
|
||||
// return user.getPasswordHash();
|
||||
// }
|
||||
//
|
||||
// return new byte[0];
|
||||
// }
|
||||
//
|
||||
// public
|
||||
// Group getGroup(final UUID uuid) {
|
||||
// return groups.();
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// public synchronized final boolean isValidUser(String userName, char[] password) {
|
||||
// String storedToken = properties.get(AdminActions.USER_PREFIX + userName, String.class);
|
||||
// String storedPasswd = properties.get(AdminActions.USER_PWD_PREFIX + userName, String.class);
|
||||
//
|
||||
// if (storedToken == null || storedToken.isEmpty()) {
|
||||
// return false;
|
||||
// } else {
|
||||
// ifObject (!token.equals(storedToken)) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// // check to see if the password matches
|
||||
//// return SCrypt.check(password, storedPasswd);
|
||||
// }
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user