Probably done with ACME support

Let's Encrypt
This commit is contained in:
Norbi Peti 2017-06-01 21:19:11 +02:00
parent e05c7230a6
commit 9ed0a5580b
4 changed files with 60 additions and 47 deletions

24
pom.xml
View file

@ -42,16 +42,24 @@
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>org.shredzone.acme4j:acme4j-client</include>
</includes>
</artifactSet>
<!-- <artifactSet> <includes> <include>org.shredzone.acme4j:acme4j-client</include>
<include>org.shredzone.acme4j:acme4j-utils</include> <include>org.bouncycastle:bcprov-jdk15on</include>
</includes> </artifactSet> -->
<pluginExecution>
<action>
<execute />
</action>
</pluginExecution>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
@ -82,35 +90,41 @@
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.9.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.TBMCPlugins.ButtonCore</groupId>
<artifactId>ButtonCore</artifactId>
<version>master-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.shredzone.acme4j</groupId>

View file

@ -13,10 +13,12 @@
*/ //Modified
package buttondevteam.website;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.net.URI;
import java.security.KeyPair;
@ -25,8 +27,6 @@ import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collection;
import javax.swing.JOptionPane;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.shredzone.acme4j.*;
import org.shredzone.acme4j.challenge.Challenge;
@ -40,6 +40,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.website.page.AcmeChallengePage;
/**
* A simple client test tool.
@ -151,7 +152,7 @@ public class AcmeClient {
* {@link Session} to bind with
* @return {@link Registration} connected to your account
*/
private Registration findOrRegisterAccount(Session session) throws AcmeException {
private Registration findOrRegisterAccount(Session session) throws AcmeException, IOException {
Registration reg;
try {
@ -245,45 +246,31 @@ public class AcmeClient {
* Domain name to be authorized
* @return {@link Challenge} to verify
*/
@SuppressWarnings("unused")
public Challenge httpChallenge(Authorization auth, String domain) throws AcmeException {
// Find a single http-01 challenge
Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE);
if (challenge == null) {
throw new AcmeException("Found no " + Http01Challenge.TYPE + " challenge, don't know what to do...");
}
// Output the challenge, wait for acknowledge...
LOG.info("Please create a file in your web server's base directory.");
LOG.info("It must be reachable at: http://" + domain + "/.well-known/acme-challenge/" + challenge.getToken());
if (ButtonWebsiteModule.PORT == 80)
LOG.info("Storing the challenge data.");
else
LOG.info("Store the challenge data! Can't do automatically.");
LOG.info("It should be reachable at: http://" + domain + "/.well-known/acme-challenge/" + challenge.getToken());
LOG.info("File name: " + challenge.getToken());
LOG.info("Content: " + challenge.getAuthorization());
LOG.info("The file must not contain any leading or trailing whitespaces or line breaks!");
LOG.info("If you're ready, dismiss the dialog...");
StringBuilder message = new StringBuilder();
message.append("Please create a file in your web server's base directory.\n\n");
message.append("http://").append(domain).append("/.well-known/acme-challenge/").append(challenge.getToken())
.append("\n\n");
message.append("Content:\n\n");
message.append(challenge.getAuthorization());
acceptChallenge(message.toString());
LOG.info("Press any key to continue...");
if (ButtonWebsiteModule.PORT != 80)
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
ButtonWebsiteModule.addPage(new AcmeChallengePage(challenge.getToken(), challenge.getAuthorization()));
return challenge;
}
/**
* Presents the instructions for preparing the challenge validation, and waits for dismissal. If the user cancelled the dialog, an exception is thrown.
*
* @param message
* Instructions to be shown in the dialog
*/
public void acceptChallenge(String message) throws AcmeException {
int option = JOptionPane.showConfirmDialog(null, message, "Prepare Challenge", JOptionPane.OK_CANCEL_OPTION);
if (option == JOptionPane.CANCEL_OPTION) {
throw new AcmeException("User cancelled the challenge");
}
}
/**
* Presents the user a link to the Terms of Service, and asks for confirmation. If the user denies confirmation, an exception is thrown.
*
@ -292,10 +279,10 @@ public class AcmeClient {
* @param agreement
* {@link URI} of the Terms of Service
*/
public void acceptAgreement(Registration reg, URI agreement) throws AcmeException {
int option = JOptionPane.showConfirmDialog(null, "Do you accept the Terms of Service?\n\n" + agreement,
"Accept ToS", JOptionPane.YES_NO_OPTION);
if (option == JOptionPane.NO_OPTION) {
public void acceptAgreement(Registration reg, URI agreement) throws AcmeException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Do you accept the terms? (y/n)");
if (br.readLine().equalsIgnoreCase("y\n")) {
throw new AcmeException("User did not accept Terms of Service");
}
@ -312,8 +299,8 @@ public class AcmeClient {
*/
public static void main(String... args) {
if (args.length == 0) {
System.err.println("Usage: ClientTest <domain>...");
System.exit(1);
TBMCCoreAPI.SendException("Error while doing ACME!", new Exception("No domains given"));
return;
}
LOG.info("Starting up...");

View file

@ -11,11 +11,12 @@ import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.website.page.*;
public class ButtonWebsiteModule extends JavaPlugin {
public static final int PORT = 8080;
private static HttpServer server;
public ButtonWebsiteModule() {
try {
server = HttpServer.create(new InetSocketAddress((InetAddress) null, 8080), 10);
server = HttpServer.create(new InetSocketAddress((InetAddress) null, PORT), 10);
} catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while starting the webserver!", e);
}
@ -25,10 +26,12 @@ public class ButtonWebsiteModule extends JavaPlugin {
public void onEnable() {
addPage(new IndexPage());
Bukkit.getScheduler().runTaskAsynchronously(this, () -> {
this.getLogger().info("Starting webserver...");
((Runnable) server::start).run(); // Totally normal way of calling a method
this.getLogger().info("Webserver started");
Thread t = new Thread(() -> AcmeClient.main("server.figytuna.com"));
t.setContextClassLoader(getClass().getClassLoader());
t.start();
});
}

View file

@ -6,15 +6,24 @@ import buttondevteam.website.io.Response;
public class AcmeChallengePage extends Page {
public AcmeChallengePage(String token, String content) {
this.token = token;
this.content = content;
}
@Override
public String GetName() {
return ".well-known/acme-challenge";
return ".well-known/acme-challenge/" + token;
}
@Override
public Response handlePage(HttpExchange exchange) {
// TODO Auto-generated method stub
return null;
if (content == null)
return new Response(500, "500 No content", exchange);
return new Response(200, content, exchange);
}
private String token;
private String content;
}