Initial commit (v1)
This commit is contained in:
commit
36d4aaac81
10 changed files with 1133 additions and 0 deletions
1
bin/rmireg.bat
Executable file
1
bin/rmireg.bat
Executable file
|
@ -0,0 +1 @@
|
|||
javac *.java && start rmiregistry
|
1
bin/startClient.bat
Executable file
1
bin/startClient.bat
Executable file
|
@ -0,0 +1 @@
|
|||
javac *.java && java AuctionClient
|
1
bin/startServer.bat
Executable file
1
bin/startServer.bat
Executable file
|
@ -0,0 +1 @@
|
|||
javac *.java && java AuctionServer
|
106
src/Auction.java
Executable file
106
src/Auction.java
Executable file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* AuctionProg 1.0
|
||||
* Copyright © 2016 Ben Goldsworthy (rumps)
|
||||
*
|
||||
* A program to facilitate a networked auction system.
|
||||
*
|
||||
* This file is part of AuctionProg.
|
||||
*
|
||||
* AuctionProg is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AuctionProg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AuctionProg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
** This class represents the auction server.
|
||||
**/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.security.*;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
/**
|
||||
** @author Ben Goldsworthy (rumps) <me+auctionprog@bengoldsworthy.net>
|
||||
** @version 1.0
|
||||
**/
|
||||
public interface Auction extends java.rmi.Remote {
|
||||
/**
|
||||
** Creates an auction with the given details, generating a new ID for
|
||||
** it.
|
||||
**
|
||||
** @param desc The auction description.
|
||||
** @param owner The auction owner/creator.
|
||||
** @param startingPrice The auction starting price.
|
||||
** @param reserve The auction reserve price.
|
||||
**/
|
||||
public void createAuction(String desc, UserWrapper owner, float startingPrice, float reserve) throws java.rmi.RemoteException;
|
||||
|
||||
/**
|
||||
** Removes an auction, provided the user calling the method owns it.
|
||||
** If the reserve price was met, also returns the winning bidder.
|
||||
**
|
||||
** @param id The ID of the auction to remove.
|
||||
** @param currentUser The user calling the method.
|
||||
** @return The `UserWrapper` of the highest bidder, if applicable.
|
||||
**/
|
||||
public UserWrapper removeAuction(int id, UserWrapper currentUser) throws java.rmi.RemoteException;
|
||||
|
||||
/**
|
||||
** Bids on a given auction, provided the bid is more than the
|
||||
** current highest price.
|
||||
**
|
||||
** @param id The ID of the auction in question.
|
||||
** @param bidder The user bidding on the auction.
|
||||
** @param price The amount bid.
|
||||
**/
|
||||
public void bidOnAuction(int id, UserWrapper bidder, float price) throws java.rmi.RemoteException;
|
||||
|
||||
/**
|
||||
** Accessor Method. Retrieves a list of all the auctions.
|
||||
**
|
||||
** @return An `ArrayList` of `AuctionWrapper`s.
|
||||
**/
|
||||
public ArrayList<AuctionWrapper> getAuctions() throws java.rmi.RemoteException;
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets a user, or creates a new one if non
|
||||
** exists with the given details.
|
||||
**
|
||||
** @param name The user's name.
|
||||
** @param email The user's email address.
|
||||
** @return The relevant `UserWrapper`.
|
||||
**/
|
||||
public UserWrapper getUser(String username) throws java.rmi.RemoteException;
|
||||
|
||||
public UserWrapper registerUser(String name, String email, String username) throws java.rmi.RemoteException;
|
||||
|
||||
public void close() throws java.rmi.RemoteException;
|
||||
|
||||
public PublicKey getPublicKey() throws java.rmi.RemoteException;
|
||||
public void sendPublicKey(PublicKey key, String username) throws java.rmi.RemoteException;
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets the status resulting from the last action
|
||||
** attempted.
|
||||
**
|
||||
** @return The status message.
|
||||
**/
|
||||
public String getStatusofLast() throws java.rmi.RemoteException;
|
||||
|
||||
public byte[] challengeServer(byte[] challenge) throws java.rmi.RemoteException;
|
||||
|
||||
public byte[] getChallenge() throws java.rmi.RemoteException;
|
||||
public boolean returnChallenge(byte[] retChal, String username) throws java.rmi.RemoteException;
|
||||
}
|
||||
|
342
src/AuctionClient.java
Executable file
342
src/AuctionClient.java
Executable file
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* AuctionProg 1.0
|
||||
* Copyright © 2016 Ben Goldsworthy (rumps)
|
||||
*
|
||||
* A program to facilitate a networked auction system.
|
||||
*
|
||||
* This file is part of AuctionProg.
|
||||
*
|
||||
* AuctionProg is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AuctionProg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AuctionProg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
** This class presents the client view for interacting with the program.
|
||||
**/
|
||||
|
||||
import java.io.*;
|
||||
import java.rmi.Naming;
|
||||
import java.rmi.RemoteException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.rmi.NotBoundException;
|
||||
import java.util.*;
|
||||
import java.util.Scanner;
|
||||
import java.util.regex.Pattern;
|
||||
import java.security.*;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
/**
|
||||
** @author Ben Goldsworthy (rumps) <bgoldsworthy96 @ gmail.com>
|
||||
** @version 1.0
|
||||
**/
|
||||
public class AuctionClient {
|
||||
// This regex is used to ensure the email address entered is a valid
|
||||
// email address format
|
||||
// (Source: http://stackoverflow.com/a/153751/4580273)
|
||||
private static final Pattern rfc2822 = Pattern.compile("^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$");
|
||||
|
||||
/**
|
||||
** Displays the UI.
|
||||
**
|
||||
** @param args Command-line arguments.
|
||||
**/
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
// Create the reference to the remote object through the
|
||||
// remiregistry. This comes first because if it fails we can
|
||||
// skip doing everything else.
|
||||
Auction a = (Auction) Naming.lookup("rmi://localhost/AuctionService");
|
||||
|
||||
// Declares some variables that'll be used later on.
|
||||
Scanner in = new Scanner(System.in);
|
||||
UserWrapper currentUser = null;
|
||||
int id;
|
||||
float price;
|
||||
|
||||
// Authenticates the user, if the program is run with a username
|
||||
// as an argument. Otherwise, prompts the user to create a new
|
||||
// user.
|
||||
currentUser = login(a, (args.length > 0) ? args[0] : "server");
|
||||
|
||||
while(true) {
|
||||
// Resets the variables after each run through.
|
||||
price = 0.0f;
|
||||
|
||||
printOptions();
|
||||
|
||||
switch(in.nextLine()) {
|
||||
// This case takes auction details from the user and then
|
||||
// creates a new auction with those.
|
||||
case "1":
|
||||
createNewAuction(a, currentUser);
|
||||
break;
|
||||
// This case removes the auction with the given ID, provided it
|
||||
// is owned by the current user.
|
||||
case "2":
|
||||
deleteAuction(a, currentUser);
|
||||
break;
|
||||
// This case displays all the currently-available auctions.
|
||||
case "3":
|
||||
displayAuctions(a);
|
||||
break;
|
||||
// This case places a bid on an auction.
|
||||
case "4":
|
||||
placeBid(a, currentUser);
|
||||
break;
|
||||
// This case exits the program.
|
||||
case "5":
|
||||
System.exit(1);
|
||||
break;
|
||||
// The below cases are remote debug commands.
|
||||
// This case remotely shuts down the server.
|
||||
case "6":
|
||||
a.close();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
}
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private static UserWrapper login(Auction a, String username) throws java.rmi.RemoteException, java.security.NoSuchAlgorithmException, java.security.InvalidKeyException, java.security.SignatureException {
|
||||
UserWrapper user = null;
|
||||
|
||||
// If the user has run the program with a username argument,
|
||||
// authenticate that user.
|
||||
if (!username.equals("server")) {
|
||||
boolean verifies;
|
||||
byte[] challenge, serverResponse, userResponse;
|
||||
Signature signed, signing;
|
||||
|
||||
// Sends the server a number to sign with its private key.
|
||||
System.out.println("Authenticating server...");
|
||||
|
||||
challenge = new byte[1024];
|
||||
new Random().nextBytes(challenge);
|
||||
serverResponse = a.challengeServer(challenge);
|
||||
|
||||
signed = Signature.getInstance("SHA1withDSA");
|
||||
signed.initVerify(readKey());
|
||||
signed.update(challenge);
|
||||
|
||||
verifies = signed.verify(serverResponse);
|
||||
System.out.println("server signature verifies: " + verifies);
|
||||
|
||||
// Receives a number from the server to sign with the user's
|
||||
// private key.
|
||||
System.out.println("Authenticating user '"+username+"'...");
|
||||
|
||||
challenge = a.getChallenge();
|
||||
|
||||
signing = Signature.getInstance("SHA1withDSA");
|
||||
signing.initSign(readKey(username));
|
||||
signing.update(challenge);
|
||||
userResponse = signing.sign();
|
||||
|
||||
verifies = a.returnChallenge(userResponse, username);
|
||||
System.out.println(username+" authenticated by server: " + verifies);
|
||||
|
||||
// Closes the program on authentication fail.
|
||||
if (!verifies) System.exit(-1);
|
||||
|
||||
// Otherwise, load the user and move on.
|
||||
user = a.getUser(username);
|
||||
System.out.println(a.getStatusofLast());
|
||||
// If the user has run the program with no arguments, they are
|
||||
// prompted to create a new user.
|
||||
} else {
|
||||
String name = "", email = "";
|
||||
Scanner in = new Scanner(System.in);
|
||||
|
||||
while (user == null) {
|
||||
System.out.print("Enter name: ");
|
||||
name = in.nextLine();
|
||||
|
||||
System.out.print("Enter email: ");
|
||||
while (!rfc2822.matcher(email).matches()) {
|
||||
email = in.nextLine();
|
||||
if (!rfc2822.matcher(email).matches()) System.out.println("\nError: invalid email address\n");
|
||||
}
|
||||
|
||||
while (username.equals("server")) {
|
||||
System.out.print("Enter username ('server' is prohibited): ");
|
||||
username = in.nextLine();
|
||||
}
|
||||
|
||||
user = a.registerUser(name, email, username);
|
||||
System.out.println(a.getStatusofLast());
|
||||
}
|
||||
|
||||
// Upon a successful user creation, new keys are generated and
|
||||
// exchanged with the server.
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
|
||||
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||
keyGen.initialize(1024, random);
|
||||
|
||||
KeyPair pair = keyGen.generateKeyPair();
|
||||
writeKey(pair.getPrivate(), username);
|
||||
a.sendPublicKey(pair.getPublic(), username);
|
||||
writeKey(a.getPublicKey(), "server");
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
private static void printOptions() {
|
||||
System.out.println("1\tCreate auction\n2\tDelete auction\n3\tView auctions\n4\tBid on auction\n5\tQuit\n6\tClose server");
|
||||
System.out.print("Choose option: ");
|
||||
}
|
||||
|
||||
private static void createNewAuction(Auction a, UserWrapper currentUser) throws java.rmi.RemoteException {
|
||||
float startPrice = 0.0f;
|
||||
float reservePrice = 0.0f;
|
||||
Scanner in = new Scanner(System.in);
|
||||
|
||||
try {
|
||||
System.out.print("Enter description: ");
|
||||
String desc = in.nextLine();
|
||||
|
||||
System.out.print("Enter starting price: \u00A3");
|
||||
startPrice = Float.parseFloat(in.nextLine());
|
||||
|
||||
while (reservePrice <= startPrice) {
|
||||
System.out.print("Enter reserve price (must be higher than starting price): \u00A3");
|
||||
reservePrice = Float.parseFloat(in.nextLine());
|
||||
}
|
||||
|
||||
a.createAuction(desc, currentUser, startPrice, reservePrice);
|
||||
System.out.println(a.getStatusofLast());
|
||||
} catch(NumberFormatException ex){
|
||||
System.out.println("\nError: not a valid price\n");
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteAuction(Auction a, UserWrapper currentUser) throws java.rmi.RemoteException {
|
||||
int id;
|
||||
UserWrapper winner;
|
||||
Scanner in = new Scanner(System.in);
|
||||
|
||||
if (!a.getAuctions().isEmpty()) {
|
||||
System.out.print("Enter auction number: ");
|
||||
id = Integer.parseInt(in.nextLine());
|
||||
|
||||
try {
|
||||
winner = a.removeAuction(id, currentUser);
|
||||
System.out.println("\nAuction won by: "+winner.getName()+" <"+winner.getEmail()+">\n");
|
||||
} catch(NullPointerException e) {
|
||||
System.out.println(a.getStatusofLast());
|
||||
}
|
||||
} else {
|
||||
System.out.println("\nNo auctions available\n");
|
||||
}
|
||||
}
|
||||
|
||||
private static void displayAuctions(Auction a) throws java.rmi.RemoteException {
|
||||
if (!a.getAuctions().isEmpty()) {
|
||||
System.out.println("#\tOwner\tPrice\tDesc");
|
||||
for (int i = 0; i < 80; i++) System.out.print("-");
|
||||
for(AuctionWrapper auction: a.getAuctions()){
|
||||
System.out.println(auction.getID()+"\t"+auction.getOwner().getUsername()+"\t\u00A3"+String.format("%.2f", auction.getPrice())+"\t"+auction.getDesc());
|
||||
}
|
||||
System.out.println("");
|
||||
} else {
|
||||
System.out.println("\nNo auctions available\n");
|
||||
}
|
||||
}
|
||||
|
||||
private static void placeBid(Auction a, UserWrapper currentUser) throws java.rmi.RemoteException {
|
||||
Scanner in = new Scanner(System.in);
|
||||
|
||||
if (!a.getAuctions().isEmpty()) {
|
||||
try{
|
||||
int id;
|
||||
float price;
|
||||
|
||||
System.out.print("Enter auction number: ");
|
||||
id = Integer.parseInt(in.nextLine());
|
||||
|
||||
System.out.print("Enter bid amount: \u00A3");
|
||||
price = Float.parseFloat(in.nextLine());
|
||||
|
||||
a.bidOnAuction(id, currentUser, price);
|
||||
System.out.println(a.getStatusofLast());
|
||||
} catch(NumberFormatException ex){
|
||||
System.out.println("\nError: not a valid price\n");
|
||||
}
|
||||
} else {
|
||||
System.out.println("\nNo auctions available\n");
|
||||
}
|
||||
}
|
||||
|
||||
private static PrivateKey readKey(String username) {
|
||||
try {
|
||||
FileInputStream keyfis = new FileInputStream(username + "priv.key");
|
||||
byte[] encKey = new byte[keyfis.available()];
|
||||
keyfis.read(encKey);
|
||||
keyfis.close();
|
||||
|
||||
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey);
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
|
||||
return keyFactory.generatePrivate(privKeySpec);
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private static PublicKey readKey() {
|
||||
try {
|
||||
FileInputStream keyfis = new FileInputStream("serverpub.key");
|
||||
byte[] encKey = new byte[keyfis.available()];
|
||||
keyfis.read(encKey);
|
||||
keyfis.close();
|
||||
|
||||
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
|
||||
return keyFactory.generatePublic(pubKeySpec);
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeKey(PrivateKey pKey, String username) {
|
||||
wK(pKey, username, "priv");
|
||||
}
|
||||
private static void writeKey(PublicKey pKey, String username) {
|
||||
wK(pKey, username, "pub");
|
||||
}
|
||||
private static void wK(Key pKey, String username, String type) {
|
||||
try {
|
||||
byte[] key = pKey.getEncoded();
|
||||
FileOutputStream keyfos = new FileOutputStream(username+type+".key");
|
||||
keyfos.write(key);
|
||||
keyfos.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
}
|
389
src/AuctionImpl.java
Executable file
389
src/AuctionImpl.java
Executable file
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* AuctionProg 1.0
|
||||
* Copyright © 2016 Ben Goldsworthy (rumps)
|
||||
*
|
||||
* A program to facilitate a networked auction system.
|
||||
*
|
||||
* This file is part of AuctionProg.
|
||||
*
|
||||
* AuctionProg is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AuctionProg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AuctionProg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
** This class provides the impementation for the AuctionServer.
|
||||
**/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.security.*;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
/**
|
||||
** @author Ben Goldsworthy (rumps) <me+auctionprog@bengoldsworthy.net>
|
||||
** @version 1.0
|
||||
**/
|
||||
public class AuctionImpl extends java.rmi.server.UnicastRemoteObject implements Auction {
|
||||
private ArrayList<AuctionWrapper> auctions;
|
||||
private ArrayList<UserWrapper> users;
|
||||
String status;
|
||||
byte[] challenge = new byte[1024];
|
||||
|
||||
/**
|
||||
** Constructor Method. Required to declare the `RemoteException`
|
||||
** instance.
|
||||
**/
|
||||
public AuctionImpl() throws java.rmi.RemoteException {
|
||||
super();
|
||||
|
||||
System.out.println("Server initilising...");
|
||||
|
||||
auctions = new ArrayList<AuctionWrapper>();
|
||||
users = new ArrayList<UserWrapper>();
|
||||
status = "";
|
||||
generateKeys();
|
||||
|
||||
System.out.println("Server start successful.");
|
||||
}
|
||||
|
||||
private void generateKeys() {
|
||||
try {
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
|
||||
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||
keyGen.initialize(1024, random);
|
||||
|
||||
KeyPair pair = keyGen.generateKeyPair();
|
||||
writeKey(pair.getPublic());
|
||||
writeKey(pair.getPrivate());
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Creates an auction with the given details, generating a new ID for
|
||||
** it.
|
||||
**
|
||||
** @param desc The auction description.
|
||||
** @param owner The auction owner/creator.
|
||||
** @param startingPrice The auction starting price.
|
||||
** @param reserve The auction reserve price.
|
||||
**/
|
||||
public void createAuction(String desc, UserWrapper owner, float startingPrice, float reserve) throws java.rmi.RemoteException {
|
||||
int id = 0;
|
||||
String preamble = "Create new auction: ";
|
||||
|
||||
lines();
|
||||
System.out.println(preamble + "begin.");
|
||||
|
||||
// Gives the new auction the lowest unclaimed ID.
|
||||
for(AuctionWrapper item: auctions){
|
||||
if (id <= item.getID()) {
|
||||
id = item.getID();
|
||||
}
|
||||
}
|
||||
|
||||
auctions.add(new AuctionWrapper(++id, desc, owner, startingPrice, reserve));
|
||||
System.out.println(preamble + "auction "+id+" successfully created.");
|
||||
status = "Auction no. "+id+" successfully created.";
|
||||
|
||||
System.out.println(preamble + "end.");
|
||||
lines();
|
||||
}
|
||||
|
||||
/**
|
||||
** Removes an auction, provided the user calling the method owns it.
|
||||
** If the reserve price was met, also returns the winning bidder.
|
||||
**
|
||||
** @param id The ID of the auction to remove.
|
||||
** @param currentUser The user calling the method.
|
||||
** @return The `UserWrapper` of the highest bidder, if applicable.
|
||||
**/
|
||||
public UserWrapper removeAuction(int id, UserWrapper currentUser) throws java.rmi.RemoteException {
|
||||
AuctionWrapper auction = this.getAuction(id);
|
||||
UserWrapper response = null;
|
||||
String preamble = "Close auction "+id+": ";
|
||||
|
||||
lines();
|
||||
System.out.println(preamble + "begin.");
|
||||
|
||||
if (auction.getOwner().getUsername().equals(currentUser.getUsername())) {
|
||||
System.out.println(preamble + "ownership rights confirmed.");
|
||||
auctions.remove(auction);
|
||||
System.out.println(preamble + "auction successfully closed.");
|
||||
status = "Auction no. "+id+" successfully removed";
|
||||
if (auction.getPrice() >= auction.getReserve()) {
|
||||
System.out.println(preamble + "auction closed with winner.");
|
||||
status = "Auction closed - winner";
|
||||
response = auction.getHighestBidder();
|
||||
} else {
|
||||
System.out.println(preamble + "auction closed with no winner.");
|
||||
status = "Auction closed - no winner";
|
||||
}
|
||||
} else {
|
||||
System.out.println(preamble + "invalid ownership rights.");
|
||||
status = "Auction no. "+id+" could not be removed - you do not own this auction";
|
||||
}
|
||||
|
||||
System.out.println(preamble + "end.");
|
||||
lines();
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
** Bids on a given auction, provided the bid is more than the
|
||||
** current highest price.
|
||||
**
|
||||
** @param id The ID of the auction in question.
|
||||
** @param bidder The user bidding on the auction.
|
||||
** @param price The amount bid.
|
||||
**/
|
||||
public void bidOnAuction(int id, UserWrapper bidder, float price)
|
||||
throws java.rmi.RemoteException {
|
||||
AuctionWrapper auction;
|
||||
String preamble = "Bid on auction "+id+": ";
|
||||
|
||||
lines();
|
||||
System.out.println(preamble + "begin.");
|
||||
|
||||
if ((auction = this.getAuction(id)) != null) {
|
||||
if (price > auction.getPrice()) {
|
||||
this.getAuction(id).setBid(bidder, price);
|
||||
System.out.println(preamble + "bid successful.");
|
||||
status = "Bid successful";
|
||||
} else {
|
||||
System.out.println(preamble + "bid less than current highest bid.");
|
||||
status = "Price less than highest bid";
|
||||
}
|
||||
} else {
|
||||
System.out.println(preamble + "auction ID not found.");
|
||||
status = "Invalid auction ID";
|
||||
}
|
||||
|
||||
System.out.println(preamble + "end.");
|
||||
lines();
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Retrieves an auction by its ID.
|
||||
**
|
||||
** @param id The ID of the auction to retrieve.
|
||||
** @return The `AuctionWrapper` indicated.
|
||||
**/
|
||||
private AuctionWrapper getAuction(int id) {
|
||||
for(AuctionWrapper auction: auctions){
|
||||
if (auction.getID() == id) {
|
||||
return auction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Retrieves a list of all the auctions.
|
||||
**
|
||||
** @return An `ArrayList` of `AuctionWrapper`s.
|
||||
**/
|
||||
public ArrayList<AuctionWrapper> getAuctions() throws java.rmi.RemoteException {
|
||||
return auctions;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets a user, or creates a new one if non
|
||||
** exists with the given details.
|
||||
**
|
||||
** @param name The user's name.
|
||||
** @param email The user's email address.
|
||||
** @return The relevant `UserWrapper`.
|
||||
**/
|
||||
public UserWrapper getUser(String username) throws java.rmi.RemoteException {
|
||||
for(UserWrapper user: users){
|
||||
if (user.getUsername().equals(username)) {
|
||||
status = "Welcome back, "+user.getName()+".";
|
||||
return user;
|
||||
}
|
||||
}
|
||||
status = "No such user.";
|
||||
return null;
|
||||
}
|
||||
|
||||
public UserWrapper registerUser(String name, String email, String username) throws java.rmi.RemoteException {
|
||||
for(UserWrapper user: users){
|
||||
if (user.getUsername().equals(username)) {
|
||||
status = "Username taken. Either choose a new username or, if trying to login to an existing account, rerun the program as 'AuctionClient <username>'.";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
UserWrapper user = new UserWrapper(name, email, username);
|
||||
users.add(user);
|
||||
status = "New user created. Hello "+name+".";
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets the status resulting from the last action
|
||||
** attempted.
|
||||
**
|
||||
** @return The status message.
|
||||
**/
|
||||
public String getStatusofLast() {
|
||||
return "\n"+status+"\n";
|
||||
}
|
||||
|
||||
public PublicKey getPublicKey() throws java.rmi.RemoteException {
|
||||
return this.readKey("server");
|
||||
}
|
||||
|
||||
public void sendPublicKey(PublicKey key, String username) throws java.rmi.RemoteException {
|
||||
this.writeKey(key, username);
|
||||
}
|
||||
|
||||
private static void writeKey(PrivateKey pKey) throws java.rmi.RemoteException {
|
||||
try {
|
||||
byte[] key = pKey.getEncoded();
|
||||
FileOutputStream keyfos = new FileOutputStream("../key/serverpriv.key");
|
||||
keyfos.write(key);
|
||||
keyfos.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeKey(PublicKey pKey) throws java.rmi.RemoteException {
|
||||
try {
|
||||
byte[] key = pKey.getEncoded();
|
||||
FileOutputStream keyfos = new FileOutputStream("../key/serverpub.key");
|
||||
keyfos.write(key);
|
||||
keyfos.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeKey(PublicKey pKey, String username) throws java.rmi.RemoteException {
|
||||
try {
|
||||
byte[] key = pKey.getEncoded();
|
||||
FileOutputStream keyfos = new FileOutputStream("../key/"+username+"pub.key");
|
||||
keyfos.write(key);
|
||||
keyfos.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static PrivateKey readKey() throws java.rmi.RemoteException {
|
||||
try {
|
||||
FileInputStream keyfis = new FileInputStream("../key/serverpriv.key");
|
||||
byte[] encKey = new byte[keyfis.available()];
|
||||
keyfis.read(encKey);
|
||||
keyfis.close();
|
||||
|
||||
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey);
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
|
||||
return keyFactory.generatePrivate(privKeySpec);
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static PublicKey readKey(String username) throws java.rmi.RemoteException {
|
||||
try {
|
||||
FileInputStream keyfis = new FileInputStream("../key/"+username+"pub.key");
|
||||
byte[] encKey = new byte[keyfis.available()];
|
||||
keyfis.read(encKey);
|
||||
|
||||
keyfis.close();
|
||||
|
||||
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
|
||||
return keyFactory.generatePublic(pubKeySpec);
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public byte[] challengeServer(byte[] challenge) throws java.rmi.RemoteException {
|
||||
try {
|
||||
Signature dsa = Signature.getInstance("SHA1withDSA");
|
||||
dsa.initSign(this.readKey());
|
||||
dsa.update(challenge);
|
||||
byte[] realSig = dsa.sign();
|
||||
|
||||
return realSig;
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getChallenge() throws java.rmi.RemoteException {
|
||||
challenge = new byte[1024];
|
||||
new Random().nextBytes(this.challenge);
|
||||
return this.challenge;
|
||||
}
|
||||
|
||||
public boolean returnChallenge(byte[] retChal, String username) throws java.rmi.RemoteException {
|
||||
System.out.println("Authenticating user '"+username+"'...");
|
||||
for(UserWrapper user: users){
|
||||
if (user.getUsername().equals(username)) {
|
||||
try {
|
||||
Signature sig = Signature.getInstance("SHA1withDSA");
|
||||
sig.initVerify(this.readKey(username));
|
||||
|
||||
sig.update(this.challenge);
|
||||
|
||||
boolean verifies = sig.verify(retChal);
|
||||
System.out.println(username+" signature verifies: " + verifies);
|
||||
return verifies;
|
||||
} catch (Exception e) {
|
||||
System.out.println();
|
||||
System.out.println("Exception");
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("User '"+username+"' not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
public void close() throws java.rmi.RemoteException {
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private void lines() {
|
||||
for (int i = 0; i < 80; i++) System.out.print("-");
|
||||
System.out.print("\n");
|
||||
}
|
||||
}
|
||||
|
54
src/AuctionServer.java
Executable file
54
src/AuctionServer.java
Executable file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* AuctionProg 1.0
|
||||
* Copyright © 2016 Ben Goldsworthy (rumps)
|
||||
*
|
||||
* A program to facilitate a networked auction system.
|
||||
*
|
||||
* This file is part of AuctionProg.
|
||||
*
|
||||
* AuctionProg is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AuctionProg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AuctionProg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
** This class sets up the auction server using RMI.
|
||||
**/
|
||||
|
||||
import java.rmi.Naming;
|
||||
|
||||
/**
|
||||
** @author Ben Goldsworthy (rumps) <me+auctionprog@bengoldsworthy.net>
|
||||
** @version 1.0
|
||||
**/
|
||||
public class AuctionServer {
|
||||
/**
|
||||
** Constructor Method.
|
||||
**/
|
||||
public AuctionServer() {
|
||||
try {
|
||||
Auction a = new AuctionImpl();
|
||||
Naming.rebind("rmi://localhost/AuctionService", a);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Server Error: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Runs the server.
|
||||
**
|
||||
** @param args Command-line arguments.
|
||||
**/
|
||||
public static void main(String args[]) {
|
||||
new AuctionServer();
|
||||
}
|
||||
}
|
123
src/AuctionWrapper.java
Executable file
123
src/AuctionWrapper.java
Executable file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* AuctionProg 1.0
|
||||
* Copyright © 2016 Ben Goldsworthy (rumps)
|
||||
*
|
||||
* A program to facilitate a networked auction system.
|
||||
*
|
||||
* This file is part of AuctionProg.
|
||||
*
|
||||
* AuctionProg is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AuctionProg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AuctionProg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
** This class represents an Auction.
|
||||
**/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
** @author Ben Goldsworthy (rumps) <me+auctionprog@bengoldsworthy.net>
|
||||
** @version 1.0
|
||||
**/
|
||||
public class AuctionWrapper implements Serializable {
|
||||
private int id;
|
||||
private String desc;
|
||||
private UserWrapper owner;
|
||||
private UserWrapper highestBidder;
|
||||
private float price;
|
||||
private float reserve;
|
||||
|
||||
/**
|
||||
** Constructor Method.
|
||||
** @param id The ID of the auction.
|
||||
** @param desc The description of the auction.
|
||||
** @param owner The user creating the auction.
|
||||
** @param startingPrice The starting price of the auction.
|
||||
** @param reserve The reserve price of the auction.
|
||||
**/
|
||||
public AuctionWrapper(int id, String desc, UserWrapper owner, float startingPrice, float reserve){
|
||||
this.id = id;
|
||||
this.desc = desc;
|
||||
this.owner = owner;
|
||||
this.highestBidder = null;
|
||||
this.price = startingPrice;
|
||||
this.reserve = reserve;
|
||||
}
|
||||
|
||||
/**
|
||||
** Returns whether the auction has been sold on close.
|
||||
** @return Whether the auction has been sold or not.
|
||||
**/
|
||||
public boolean isSold() {
|
||||
return (this.price >= this.reserve) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
** Mutator Method. Sets the current highest bid.
|
||||
** @param bidder The user bidding.
|
||||
** @param price The bid price.
|
||||
**/
|
||||
public void setBid(UserWrapper bidder, float price) {
|
||||
this.highestBidder = bidder;
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets the auction ID.
|
||||
** @return The auction ID.
|
||||
**/
|
||||
public int getID() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets the auction description.
|
||||
** @return The auction description.
|
||||
**/
|
||||
public String getDesc() {
|
||||
return this.desc;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets the auction owner.
|
||||
** @return The auction owner.
|
||||
**/
|
||||
public UserWrapper getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets the highest bidder on the auction.
|
||||
** @return The highest bidder on the auction.
|
||||
**/
|
||||
public UserWrapper getHighestBidder() {
|
||||
return this.highestBidder;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets the current auction price.
|
||||
** @return The current auction price.
|
||||
**/
|
||||
public float getPrice() {
|
||||
return this.price;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Gets the auction reserve price.
|
||||
** @return The auction reserve price.
|
||||
**/
|
||||
public float getReserve() {
|
||||
return this.reserve;
|
||||
}
|
||||
}
|
47
src/GenSig.java
Executable file
47
src/GenSig.java
Executable file
|
@ -0,0 +1,47 @@
|
|||
import java.io.*;
|
||||
import java.security.*;
|
||||
|
||||
class GenSig {
|
||||
public static void main(String[] args) {
|
||||
/* Generate a DSA signature */
|
||||
|
||||
if (args.length != 1) {
|
||||
System.out.println("Usage: GenSig nameOfFileToSign");
|
||||
} else try {
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
|
||||
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
|
||||
keyGen.initialize(1024, random);
|
||||
|
||||
KeyPair pair = keyGen.generateKeyPair();
|
||||
PrivateKey priv = pair.getPrivate();
|
||||
PublicKey pub = pair.getPublic();
|
||||
|
||||
Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
|
||||
dsa.initSign(priv);
|
||||
|
||||
FileInputStream fis = new FileInputStream(args[0]);
|
||||
BufferedInputStream bufin = new BufferedInputStream(fis);
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = bufin.read(buffer)) >= 0) {
|
||||
dsa.update(buffer, 0, len);
|
||||
};
|
||||
bufin.close();
|
||||
|
||||
byte[] realSig = dsa.sign();
|
||||
|
||||
/* save the signature in a file */
|
||||
FileOutputStream sigfos = new FileOutputStream("sig");
|
||||
sigfos.write(realSig);
|
||||
sigfos.close();
|
||||
|
||||
/* save the public key in a file */
|
||||
byte[] key = pub.getEncoded();
|
||||
FileOutputStream keyfos = new FileOutputStream("suepk");
|
||||
keyfos.write(key);
|
||||
keyfos.close();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Caught exception " + e.toString());
|
||||
}
|
||||
}
|
||||
}
|
69
src/UserWrapper.java
Executable file
69
src/UserWrapper.java
Executable file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* AuctionProg 1.0
|
||||
* Copyright © 2016 Ben Goldsworthy (rumps)
|
||||
*
|
||||
* A program to facilitate a networked auction system.
|
||||
*
|
||||
* This file is part of AuctionProg.
|
||||
*
|
||||
* AuctionProg is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AuctionProg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AuctionProg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
** This class represents a User.
|
||||
**/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
** @author Ben Goldsworthy (rumps) <me+auctionprog@bengoldsworthy.net>
|
||||
** @version 1.0
|
||||
**/
|
||||
public class UserWrapper implements Serializable {
|
||||
private String name;
|
||||
private String email;
|
||||
private String username;
|
||||
|
||||
/**
|
||||
** Constructor Method.
|
||||
** @param id The ID of the user.
|
||||
** @param name The user's name.
|
||||
** @param email The user's email address.
|
||||
**/
|
||||
public UserWrapper(String name, String email, String username){
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Returns the user's name.
|
||||
** @param The user's name.
|
||||
**/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
** Accessor Method. Returns the user's email address.
|
||||
** @param The user's email address.
|
||||
**/
|
||||
public String getEmail() {
|
||||
return this.email;
|
||||
}
|
||||
}
|
Reference in a new issue