@@ -10,3 +10,5 @@ build | |||
/benchmarks.json | |||
/config.json | |||
/.gitignore | |||
/admins.json | |||
/keystore.jks |
@@ -13,6 +13,7 @@ | |||
</v-data-table> | |||
</v-card> | |||
<h4>Submit your own benchmarks <router-link to="/submit">here</router-link></h4> | |||
<h5>Admin panel <router-link to="/login">here</router-link></h5> | |||
</div> | |||
</template> | |||
@@ -32,6 +33,10 @@ export default { | |||
text: "Model", | |||
value: "model" | |||
}, | |||
{ | |||
text: "Memory", | |||
value: "memory" | |||
}, | |||
{ | |||
text: "Hashrate (h/s)", | |||
value: "hashrate" | |||
@@ -7,6 +7,7 @@ | |||
<v-form class="submit-form" v-model="valid"> | |||
<v-text-field v-model="vendor" autocomplete="vendor" label="Vendor" required></v-text-field> | |||
<v-text-field v-model="model" autocomplete="model" label="Model" required></v-text-field> | |||
<v-text-field v-model="memory" autocomplete="memory" label="Memory" required></v-text-field> | |||
<v-text-field v-model="hashrate" autocomplete="hashrate" label="Hashrate" required></v-text-field> | |||
<v-text-field v-model="miner" autocomplete="miner" label="Miner" required></v-text-field> | |||
<v-text-field v-model="user" autocomplete="user" label="User" class="text-field" equired></v-text-field> | |||
@@ -24,6 +25,7 @@ export default { | |||
valid: false, | |||
vendor: "", | |||
model: "", | |||
memory: "", | |||
hashrate: "", | |||
miner: "", | |||
user: "", | |||
@@ -42,6 +44,7 @@ export default { | |||
body: JSON.stringify({ | |||
vendor: this.vendor, | |||
model: this.model, | |||
memory: this.memory, | |||
hashrate: this.hashrate, | |||
minerVersion: this.miner, | |||
owner: this.user | |||
@@ -38,6 +38,10 @@ export default { | |||
text: "Model", | |||
value: "model" | |||
}, | |||
{ | |||
text: "Memory", | |||
value: "memory" | |||
}, | |||
{ | |||
text: "Hashrate (h/s)", | |||
value: "hashrate" | |||
@@ -4,17 +4,19 @@ public class Benchmark { | |||
private int id; | |||
private Vendor vendor; //AMD | |||
private String model; //Ryzen 5 3600X | |||
private String model; //Ryzen 5 3600X | |||
private String memory; | |||
private long hashrate; //550h/s | |||
private String minerVersion; //XMRig 5.9.0 | |||
private String owner; //Owner | |||
private long timestamp; //Submitted on 08/03/2020 | |||
public Benchmark(int id, Vendor vendor, String model, long hashrate, String minerVersion, String owner, long timestamp) | |||
public Benchmark(int id, Vendor vendor, String model, String memory, long hashrate, String minerVersion, String owner, long timestamp) | |||
{ | |||
this.id = id; | |||
this.vendor = vendor; | |||
this.model = model; | |||
this.memory = memory; | |||
this.hashrate = hashrate; | |||
this.minerVersion = minerVersion; | |||
this.owner = owner; | |||
@@ -41,6 +43,11 @@ public class Benchmark { | |||
return model; | |||
} | |||
public String getMemory() | |||
{ | |||
return memory; | |||
} | |||
public long getHashrate() | |||
{ | |||
return hashrate; | |||
@@ -64,7 +71,7 @@ public class Benchmark { | |||
@Override | |||
public String toString() | |||
{ | |||
return String.format("Benchmark[vendor=%s, model=%s, hashrate=%d, owner=%s, timestamp=%d]", vendor.name(), model, hashrate, owner, timestamp); | |||
return String.format("Benchmark[vendor=%s, model=%s, memory=%s, hashrate=%d, owner=%s, timestamp=%d]", vendor.name(), model, memory, hashrate, owner, timestamp); | |||
} | |||
public static enum Vendor { | |||
@@ -1,8 +1,5 @@ | |||
package fr.slixe.benchmarks.http; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import fr.litarvan.paladin.AfterEvent; | |||
import fr.litarvan.paladin.BeforeEvent; | |||
import fr.litarvan.paladin.Session; | |||
@@ -15,7 +12,7 @@ import fr.slixe.benchmarks.User; | |||
public class AuthMiddleware extends Middleware | |||
{ | |||
private static final Logger log = LoggerFactory.getLogger("Auth Middleware"); | |||
//private static final Logger log = LoggerFactory.getLogger("Auth Middleware"); | |||
@Override | |||
public void before(BeforeEvent event, Request request, Response response, Route route) throws RequestException | |||
@@ -24,9 +21,9 @@ public class AuthMiddleware extends Middleware | |||
if (session == null || session.get(User.class) == null) { | |||
throw new UnauthorizedOperationException(); | |||
} | |||
else { | |||
log.info("{}", session.get(User.class)); | |||
} | |||
/*else { | |||
log.info("{} from {}", session.get(User.class).getUsername(), request.getIp()); | |||
}*/ | |||
} | |||
@Override | |||
@@ -0,0 +1,11 @@ | |||
package fr.slixe.benchmarks.http; | |||
import fr.litarvan.paladin.http.routing.RequestException; | |||
public class RateLimitException extends RequestException { | |||
public RateLimitException(String message) { | |||
super(message); | |||
} | |||
} |
@@ -8,6 +8,7 @@ import com.google.inject.Inject | |||
import fr.litarvan.paladin.Paladin | |||
import fr.litarvan.paladin.Session | |||
import fr.litarvan.paladin.http.Controller | |||
import fr.litarvan.paladin.http.Request | |||
import fr.litarvan.paladin.http.routing.JsonBody | |||
import fr.litarvan.paladin.http.routing.RequestParams | |||
import fr.slixe.benchmarks.User | |||
@@ -27,13 +28,13 @@ public class AuthController extends Controller { | |||
@JsonBody | |||
@RequestParams(required = ["username", "password"]) | |||
def login(String username, String password) | |||
def login(String username, String password, Request request) | |||
{ | |||
if (password.length() > 64) { | |||
throw new InvalidParameterException("Password is too long") | |||
} | |||
User user = authService.loginUsername(username, password) | |||
User user = authService.loginUsername(username, password, request.ip) | |||
if (user == null) { | |||
throw new InvalidParameterException("Username or password is incorrect") | |||
@@ -49,12 +49,12 @@ public class MainController extends Controller { | |||
* @param String owner (Slixe) | |||
*/ | |||
@JsonBody | |||
@RequestParams(required = ["vendor", "model", "hashrate", "minerVersion", "owner"]) | |||
def submit(Vendor vendor, String model, long hashrate, String minerVersion, String owner) | |||
@RequestParams(required = ["vendor", "model", "memory", "hashrate", "minerVersion", "owner"]) | |||
def submit(Vendor vendor, String model, String memory, long hashrate, String minerVersion, String owner) | |||
{ | |||
log.debug("A new benchmark has been submitted!") | |||
Benchmark benchmark = new Benchmark(benchmarkService.lastUnconfirmedBenchId(), vendor, model, hashrate, minerVersion, owner, System.currentTimeMillis()) | |||
Benchmark benchmark = new Benchmark(benchmarkService.lastUnconfirmedBenchId(), vendor, model, memory, hashrate, minerVersion, owner, System.currentTimeMillis()) | |||
benchmarkService.addUnconfirmedBenchmarks(benchmark) | |||
[ | |||
@@ -23,6 +23,7 @@ public class BenchmarkAdapter implements JsonSerializer<Benchmark>, JsonDeserial | |||
json.addProperty("id", src.getId()); | |||
json.addProperty("vendor", src.getVendor().name()); | |||
json.addProperty("model", src.getModel()); | |||
json.addProperty("memory", src.getMemory()); | |||
json.addProperty("hashrate", src.getHashrate()); | |||
json.addProperty("minerVersion", src.getMinerVersion()); | |||
json.addProperty("owner", src.getOwner()); | |||
@@ -39,11 +40,12 @@ public class BenchmarkAdapter implements JsonSerializer<Benchmark>, JsonDeserial | |||
int id = json.get("id").getAsInt(); | |||
Vendor vendor = Vendor.valueOf(json.get("vendor").getAsString()); | |||
String model = json.get("model").getAsString(); | |||
String memory = json.get("memory").getAsString(); | |||
long hashrate = json.get("hashrate").getAsLong(); | |||
String minerVersion = json.get("minerVersion").getAsString(); | |||
String owner = json.get("owner").getAsString(); | |||
long timestamp = json.get("timestamp").getAsLong(); | |||
return new Benchmark(id, vendor, model, hashrate, minerVersion, owner, timestamp); | |||
return new Benchmark(id, vendor, model, memory, hashrate, minerVersion, owner, timestamp); | |||
} | |||
} |
@@ -31,7 +31,7 @@ public class UserAdapter implements JsonSerializer<User>, JsonDeserializer<User> | |||
} | |||
else if (jsonObject.has("hashedPassword")) { | |||
hashedPassword = jsonObject.get("hashedPassword").getAsString(); | |||
hashedPassword = jsonObject.get("hashedPassword").getAsString(); | |||
} | |||
return new User(username, hashedPassword, salt); | |||
@@ -5,8 +5,10 @@ import java.io.FileReader; | |||
import java.io.FileWriter; | |||
import java.io.IOException; | |||
import java.lang.reflect.Type; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.WeakHashMap; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import org.slf4j.Logger; | |||
@@ -21,13 +23,16 @@ import com.google.inject.Inject; | |||
import com.google.inject.Singleton; | |||
import fr.slixe.benchmarks.User; | |||
import fr.slixe.benchmarks.http.RateLimitException; | |||
@Singleton | |||
public class AuthService { | |||
private static final int RATE_LIMIT = 1500; | |||
private static final Type USER_TYPE = new TypeToken<List<User>>(){}.getType(); | |||
private static final Logger log = LoggerFactory.getLogger("DERO Auth Service"); | |||
private final Map<String, Long> requests = Collections.synchronizedMap(new WeakHashMap<>()); //there is no weak map impl for TObjectLongMap (trove4j) | |||
private final Map<String, User> users = new ConcurrentHashMap<>(); | |||
private final File file = new File("admins.json"); | |||
@@ -55,13 +60,22 @@ public class AuthService { | |||
{ | |||
this.users.put(user.getUsername(), user); | |||
} | |||
jsonReader.close(); | |||
} catch (IOException e) { | |||
log.error(e.getMessage()); | |||
} | |||
saveUsers(); | |||
} | |||
private void saveUsers() | |||
{ | |||
try (FileWriter fileWriter = new FileWriter(this.file)) { | |||
gson.toJson(this.users.values(), USER_TYPE, fileWriter); | |||
} catch (IOException e) { | |||
log.error(e.getMessage()); | |||
} | |||
} | |||
private void createExampleUser() | |||
{ | |||
String username = "Slixe"; | |||
@@ -69,21 +83,26 @@ public class AuthService { | |||
String salt = "salt123"; | |||
this.users.put(username, new User(username, AuthService.hash(password, salt), salt)); | |||
try (FileWriter fileWriter = new FileWriter(this.file)) { | |||
gson.toJson(this.users.values(), USER_TYPE, fileWriter); | |||
} catch (IOException e) { | |||
log.error(e.getMessage()); | |||
} | |||
} | |||
public User loginUsername(String username, String password) | |||
public User loginUsername(String username, String password, String ip) throws RateLimitException | |||
{ | |||
return login(users.get(username), password); | |||
return login(users.get(username), password, ip); | |||
} | |||
public User login(User user, String password) | |||
public User login(User user, String password, String ip) throws RateLimitException | |||
{ | |||
if (!this.requests.containsKey(ip)) { | |||
this.requests.put(ip, System.currentTimeMillis()); | |||
} else { | |||
long lastTime = this.requests.get(ip); | |||
this.requests.put(ip, System.currentTimeMillis()); | |||
if (System.currentTimeMillis() <= (lastTime + RATE_LIMIT)) { | |||
log.warn("Rate limit for IP {}", ip); | |||
throw new RateLimitException("You must wait 1.5s between each request!"); | |||
} | |||
} | |||
if (user == null) { | |||
return null; | |||
} | |||
@@ -94,6 +113,10 @@ public class AuthService { | |||
{ | |||
return null; | |||
} | |||
if (this.requests.containsKey(ip)) { | |||
this.requests.remove(ip); | |||
} | |||
return user; | |||
} | |||