Commit a21a98d3 authored by Dominik Rosiek's avatar Dominik Rosiek

Merge branch 'master' of gitlab.telemabk.pl:jifwin/CTF

parents 99821629 70a1e723
...@@ -85,8 +85,10 @@ textTasks: ...@@ -85,8 +85,10 @@ textTasks:
flags: flags:
- value: "KYN2016_KominiarkaAtrybutemHakera" - value: "KYN2016_KominiarkaAtrybutemHakera"
description: "Umiesz się bawić" description: "Umiesz się bawić"
points: 1
- value: "AGH_sdfg1f1" - value: "AGH_sdfg1f1"
description: "flaga 1" description: "flaga 1"
points: 2
- name: "Inne" - name: "Inne"
text: "Wszystko inne" text: "Wszystko inne"
...@@ -95,6 +97,7 @@ textTasks: ...@@ -95,6 +97,7 @@ textTasks:
flags: flags:
- value: "KYN2016_UmiemCzytacRegulaminy" - value: "KYN2016_UmiemCzytacRegulaminy"
description: "Wiem w co gram" description: "Wiem w co gram"
points: 3
- name: "UI" - name: "UI"
text: "Znajdz flagi w jułaju" text: "Znajdz flagi w jułaju"
...@@ -103,16 +106,22 @@ textTasks: ...@@ -103,16 +106,22 @@ textTasks:
flags: flags:
- value: "KYN2016_TervetullutKotisivuilleni" - value: "KYN2016_TervetullutKotisivuilleni"
description: "Tytuł" description: "Tytuł"
points: 4
- value: "KYN2016_ToNieprawda" - value: "KYN2016_ToNieprawda"
description: "Poezja" description: "Poezja"
points: 5
- value: "KYN2016_EmacsemPrzezSendmaila" - value: "KYN2016_EmacsemPrzezSendmaila"
description: "Konsola" description: "Konsola"
points: 6
- value: "KYN2016_SzukajDalejAZnajdzieszWiecej" - value: "KYN2016_SzukajDalejAZnajdzieszWiecej"
description: "QR" description: "QR"
points: 7
- value: "KYN2016_BROWAR" - value: "KYN2016_BROWAR"
description: "Rebus" description: "Rebus"
points: 8
- value: "KYN2016_RUAHACKER?" - value: "KYN2016_RUAHACKER?"
description: "Tunel" description: "Tunel"
points: 9
webTasks: webTasks:
...@@ -123,8 +132,10 @@ webTasks: ...@@ -123,8 +132,10 @@ webTasks:
flags: flags:
- value: "KYN2016_WartoSieGlowic" - value: "KYN2016_WartoSieGlowic"
description: "Dodanie nagłówka" description: "Dodanie nagłówka"
points: 5
- value: "KYN2016_PatriInterentu" - value: "KYN2016_PatriInterentu"
description: "Remote File Include" description: "Remote File Include"
points: 3
- name: "Zadanie testowe nr 7" - name: "Zadanie testowe nr 7"
description: "Opis zadania testowego. Usunąć w wersji produkcyjnej." description: "Opis zadania testowego. Usunąć w wersji produkcyjnej."
...@@ -133,6 +144,7 @@ webTasks: ...@@ -133,6 +144,7 @@ webTasks:
flags: flags:
- value: "KYN2016_OpenYourEyes" - value: "KYN2016_OpenYourEyes"
description: "Kod źródłowy" description: "Kod źródłowy"
points: 2
- name: "Wiadomość od Alicji" - name: "Wiadomość od Alicji"
description: "Alicja przesłała Ci wiadomość. Niestety część wiadomości jest nieczytelna, została ona zastąpiona znakami '@'. Na szczęście, za pomocą innego kanału komunikacji Alicja przesłała Ci hash md5 wiadomości, który wynosi: 047998436f086d08317249e14c5bd8c0" description: "Alicja przesłała Ci wiadomość. Niestety część wiadomości jest nieczytelna, została ona zastąpiona znakami '@'. Na szczęście, za pomocą innego kanału komunikacji Alicja przesłała Ci hash md5 wiadomości, który wynosi: 047998436f086d08317249e14c5bd8c0"
...@@ -141,6 +153,7 @@ webTasks: ...@@ -141,6 +153,7 @@ webTasks:
flags: flags:
- value: "KYN2016_87365101329846397649561156187035341" - value: "KYN2016_87365101329846397649561156187035341"
description: "MD5" description: "MD5"
points: 7
- name: "Kryptografia" - name: "Kryptografia"
description: "Z kryptografią sptykamy się codziennie. Ale czy na wiemy o niej wystarczająco wiele?. Kilka zadań z kryptografii dla rozruszania szarych komórek..." description: "Z kryptografią sptykamy się codziennie. Ale czy na wiemy o niej wystarczająco wiele?. Kilka zadań z kryptografii dla rozruszania szarych komórek..."
...@@ -149,12 +162,16 @@ webTasks: ...@@ -149,12 +162,16 @@ webTasks:
flags: flags:
- value: "KYN2016_DoubleEncoded" - value: "KYN2016_DoubleEncoded"
description: "Kombinacja kodów" description: "Kombinacja kodów"
points: 2
- value: "KYN2016_AveJaAveCezar" - value: "KYN2016_AveJaAveCezar"
description: "Cezar" description: "Cezar"
points: 3
- value: "KYN2016_SlowoOdOrganizatora" - value: "KYN2016_SlowoOdOrganizatora"
description: "Wiadomość od organizatorów" description: "Wiadomość od organizatorów"
points: 9
- value: "KYN2016_OupsChybaCosTuJest" - value: "KYN2016_OupsChybaCosTuJest"
description: "Komentarz w archiwum" description: "Komentarz w archiwum"
points: 1
- name: "Znowu kotki, pieski, krówki..." - name: "Znowu kotki, pieski, krówki..."
description: "Strona została w końcu zbudowana i wystawiona do sieci, ale czy na pewno jest bezpieczna?" description: "Strona została w końcu zbudowana i wystawiona do sieci, ale czy na pewno jest bezpieczna?"
...@@ -163,5 +180,16 @@ webTasks: ...@@ -163,5 +180,16 @@ webTasks:
flags: flags:
- value: "KYN2016_UzywamFantazyji" - value: "KYN2016_UzywamFantazyji"
description: "Niezwykły tytuł" description: "Niezwykły tytuł"
points: 2
- value: "KYN2016_LaoreetAliquet" - value: "KYN2016_LaoreetAliquet"
description: "SQLInjection" description: "SQLInjection"
points: 3
- name: "Debugging task to remove"
description: "To nie jest zadanie"
url: "http://localhost:8082/"
level: 9
flags:
- value: "flaga 1"
description: "flaga 1 desc"
points: 100
...@@ -85,8 +85,10 @@ textTasks: ...@@ -85,8 +85,10 @@ textTasks:
flags: flags:
- value: "KYN2016_KominiarkaAtrybutemHakera" - value: "KYN2016_KominiarkaAtrybutemHakera"
description: "Umiesz się bawić" description: "Umiesz się bawić"
points: 1
- value: "AGH_sdfg1f1" - value: "AGH_sdfg1f1"
description: "flaga 1" description: "flaga 1"
points: 2
- name: "Inne" - name: "Inne"
text: "Wszystko inne" text: "Wszystko inne"
...@@ -95,6 +97,7 @@ textTasks: ...@@ -95,6 +97,7 @@ textTasks:
flags: flags:
- value: "KYN2016_UmiemCzytacRegulaminy" - value: "KYN2016_UmiemCzytacRegulaminy"
description: "Wiem w co gram" description: "Wiem w co gram"
points: 3
- name: "UI" - name: "UI"
text: "Znajdz flagi w jułaju" text: "Znajdz flagi w jułaju"
...@@ -103,16 +106,22 @@ textTasks: ...@@ -103,16 +106,22 @@ textTasks:
flags: flags:
- value: "KYN2016_TervetullutKotisivuilleni" - value: "KYN2016_TervetullutKotisivuilleni"
description: "Tytuł" description: "Tytuł"
points: 4
- value: "KYN2016_ToNieprawda" - value: "KYN2016_ToNieprawda"
description: "Poezja" description: "Poezja"
points: 5
- value: "KYN2016_EmacsemPrzezSendmaila" - value: "KYN2016_EmacsemPrzezSendmaila"
description: "Konsola" description: "Konsola"
points: 6
- value: "KYN2016_SzukajDalejAZnajdzieszWiecej" - value: "KYN2016_SzukajDalejAZnajdzieszWiecej"
description: "QR" description: "QR"
points: 7
- value: "KYN2016_BROWAR" - value: "KYN2016_BROWAR"
description: "Rebus" description: "Rebus"
points: 8
- value: "KYN2016_RUAHACKER?" - value: "KYN2016_RUAHACKER?"
description: "Tunel" description: "Tunel"
points: 9
webTasks: webTasks:
...@@ -123,8 +132,10 @@ webTasks: ...@@ -123,8 +132,10 @@ webTasks:
flags: flags:
- value: "KYN2016_WartoSieGlowic" - value: "KYN2016_WartoSieGlowic"
description: "Dodanie nagłówka" description: "Dodanie nagłówka"
points: 5
- value: "KYN2016_PatriInterentu" - value: "KYN2016_PatriInterentu"
description: "Remote File Include" description: "Remote File Include"
points: 3
- name: "Zadanie testowe nr 7" - name: "Zadanie testowe nr 7"
description: "Opis zadania testowego. Usunąć w wersji produkcyjnej." description: "Opis zadania testowego. Usunąć w wersji produkcyjnej."
...@@ -133,6 +144,7 @@ webTasks: ...@@ -133,6 +144,7 @@ webTasks:
flags: flags:
- value: "KYN2016_OpenYourEyes" - value: "KYN2016_OpenYourEyes"
description: "Kod źródłowy" description: "Kod źródłowy"
points: 2
- name: "Wiadomość od Alicji" - name: "Wiadomość od Alicji"
description: "Alicja przesłała Ci wiadomość. Niestety część wiadomości jest nieczytelna, została ona zastąpiona znakami '@'. Na szczęście, za pomocą innego kanału komunikacji Alicja przesłała Ci hash md5 wiadomości, który wynosi: 047998436f086d08317249e14c5bd8c0" description: "Alicja przesłała Ci wiadomość. Niestety część wiadomości jest nieczytelna, została ona zastąpiona znakami '@'. Na szczęście, za pomocą innego kanału komunikacji Alicja przesłała Ci hash md5 wiadomości, który wynosi: 047998436f086d08317249e14c5bd8c0"
...@@ -141,6 +153,7 @@ webTasks: ...@@ -141,6 +153,7 @@ webTasks:
flags: flags:
- value: "KYN2016_87365101329846397649561156187035341" - value: "KYN2016_87365101329846397649561156187035341"
description: "MD5" description: "MD5"
points: 7
- name: "Kryptografia" - name: "Kryptografia"
description: "Z kryptografią sptykamy się codziennie. Ale czy na wiemy o niej wystarczająco wiele?. Kilka zadań z kryptografii dla rozruszania szarych komórek..." description: "Z kryptografią sptykamy się codziennie. Ale czy na wiemy o niej wystarczająco wiele?. Kilka zadań z kryptografii dla rozruszania szarych komórek..."
...@@ -149,12 +162,16 @@ webTasks: ...@@ -149,12 +162,16 @@ webTasks:
flags: flags:
- value: "KYN2016_DoubleEncoded" - value: "KYN2016_DoubleEncoded"
description: "Kombinacja kodów" description: "Kombinacja kodów"
points: 2
- value: "KYN2016_AveJaAveCezar" - value: "KYN2016_AveJaAveCezar"
description: "Cezar" description: "Cezar"
points: 3
- value: "KYN2016_SlowoOdOrganizatora" - value: "KYN2016_SlowoOdOrganizatora"
description: "Wiadomość od organizatorów" description: "Wiadomość od organizatorów"
points: 9
- value: "KYN2016_OupsChybaCosTuJest" - value: "KYN2016_OupsChybaCosTuJest"
description: "Komentarz w archiwum" description: "Komentarz w archiwum"
points: 1
- name: "Znowu kotki, pieski, krówki..." - name: "Znowu kotki, pieski, krówki..."
description: "Strona została w końcu zbudowana i wystawiona do sieci, ale czy na pewno jest bezpieczna?" description: "Strona została w końcu zbudowana i wystawiona do sieci, ale czy na pewno jest bezpieczna?"
...@@ -163,5 +180,7 @@ webTasks: ...@@ -163,5 +180,7 @@ webTasks:
flags: flags:
- value: "KYN2016_UzywamFantazyji" - value: "KYN2016_UzywamFantazyji"
description: "Niezwykły tytuł" description: "Niezwykły tytuł"
points: 2
- value: "KYN2016_LaoreetAliquet" - value: "KYN2016_LaoreetAliquet"
description: "SQLInjection" description: "SQLInjection"
points: 3
\ No newline at end of file
package com.telephoners.krakyournet.ctf.beans; package com.telephoners.krakyournet.ctf.beans;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class Flag { public class Flag {
private String value; private String value;
private String description; private String description;
private int points;
public Flag() { public Flag() {
} }
public Flag(String value, String description) { public Flag(String value, String description, int points) {
this.value = value; this.value = value;
this.description = description; this.description = description;
this.points = points;
} }
@JsonIgnore
public String getValue() { public String getValue() {
return value; return value;
} }
@JsonIgnore
public void setValue(String value) { public void setValue(String value) {
this.value = value; this.value = value;
} }
...@@ -29,4 +35,14 @@ public class Flag { ...@@ -29,4 +35,14 @@ public class Flag {
{ {
this.description = description; this.description = description;
} }
public int getPoints()
{
return points;
}
public void setPoints(int points)
{
this.points = points;
}
} }
package com.telephoners.krakyournet.ctf.beans.tasks; package com.telephoners.krakyournet.ctf.beans.tasks;
import com.telephoners.krakyournet.ctf.beans.User; import com.telephoners.krakyournet.ctf.beans.User;
import org.eclipse.jetty.http.HttpMethod;
import java.util.Map; import java.util.Map;
public class TaskRequestContext public class TaskRequestContext
{ {
private String httpMethod; //todo: use class private HttpMethod httpMethod;
private User user; private User user;
private String path; private String path;
private String body; private String body;
private Map<String, String> headers; private Map<String, String> headers;
public TaskRequestContext withHttpMethod(String httpMethod) public TaskRequestContext withHttpMethod(HttpMethod httpMethod)
{ {
this.httpMethod = httpMethod; this.httpMethod = httpMethod;
return this; return this;
...@@ -40,7 +41,7 @@ public class TaskRequestContext ...@@ -40,7 +41,7 @@ public class TaskRequestContext
return this; return this;
} }
public String getHttpMethod() public HttpMethod getHttpMethod()
{ {
return httpMethod; return httpMethod;
} }
......
package com.telephoners.krakyournet.ctf.beans.tasks;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.telephoners.krakyournet.ctf.beans.User;
import com.telephoners.krakyournet.ctf.core.ApplicationConfiguration;
import com.telephoners.krakyournet.ctf.helpers.StreamUtils;
import org.eclipse.jetty.http.HttpMethod;
import org.glassfish.jersey.server.ContainerRequest;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.MultivaluedMap;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Singleton
public class TaskRequestContextBuilder
{
private ApplicationConfiguration applicationConfiguration;
@Inject
public TaskRequestContextBuilder(ApplicationConfiguration applicationConfiguration)
{
this.applicationConfiguration = applicationConfiguration;
}
private Map<String, String> extractProxiedHeaders(MultivaluedMap<String, String> headers)
{
Set<String> proxiedHeaders = applicationConfiguration.getProxiedHeaders();
return headers.entrySet()
.stream()
.filter(header -> proxiedHeaders.contains(header.getKey()))
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().get(0) //todo: check
));
}
public TaskRequestContext from(User user, String path, ContainerRequestContext containerRequestContext) throws IOException
{
String fullPath = path;
TaskRequestContext taskRequestContext = new TaskRequestContext();
if (user != null) {
taskRequestContext.withUser(user);
}
if (path != null) {
taskRequestContext.withPath(path);
String httpMethod = containerRequestContext.getMethod();
String query = ((ContainerRequest) containerRequestContext).getRequestUri().getQuery();
if (query != null) {
fullPath += "?" + query;
}
taskRequestContext.withPath(fullPath);
if(httpMethod.equals("GET")) {
taskRequestContext.withHttpMethod(HttpMethod.GET);
}
else if (httpMethod.equals("POST")) {
taskRequestContext.withHttpMethod(HttpMethod.POST);
String body = StreamUtils.readStream(containerRequestContext.getEntityStream());
taskRequestContext.withBody(body);
}
else {
throw new IllegalStateException("Invalid http method");
}
Map<String, String> proxiedHeaders = extractProxiedHeaders(containerRequestContext.getHeaders());
taskRequestContext.withHeaders(proxiedHeaders);
}
return taskRequestContext;
}
}
...@@ -2,23 +2,29 @@ package com.telephoners.krakyournet.ctf.beans.tasks; ...@@ -2,23 +2,29 @@ package com.telephoners.krakyournet.ctf.beans.tasks;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.telephoners.krakyournet.ctf.beans.Flag; import com.telephoners.krakyournet.ctf.beans.Flag;
import com.telephoners.krakyournet.ctf.beans.User;
import com.telephoners.krakyournet.ctf.helpers.StreamUtils; import com.telephoners.krakyournet.ctf.helpers.StreamUtils;
import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.mongodb.morphia.annotations.Entity; import org.mongodb.morphia.annotations.Entity;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Entity("tasks") @Entity("tasks")
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class WebTask extends Task public class WebTask extends Task
{ {
private String url; private String url;
private static final String KYN_HEADER_NAME = "KYN_2016"; //todo
public WebTask(String name, int level, String description, List<Flag> flags, String url) public WebTask(String name, int level, String description, List<Flag> flags, String url)
{ {
...@@ -30,30 +36,35 @@ public class WebTask extends Task ...@@ -30,30 +36,35 @@ public class WebTask extends Task
{ {
} }
@Override //todo: avoid converting in both ways
public TaskResponse getTaskResponse(TaskRequestContext taskRequestContext) throws IOException private Map<String, String> buildHeadersMap(Header[] headers)
{ {
String url = getUrl() + taskRequestContext.getPath(); return Stream.of(headers)
//todo: header in .collect(Collectors.toMap(
CloseableHttpResponse response = proxyRequest(url, taskRequestContext.getUser(), null); Header::getName,
String text = StreamUtils.readStream(response.getEntity().getContent()); Header::getValue
//todo: header out ));
TaskResponse taskResponse = new TaskResponse(text, null);//todo: build with }
return taskResponse;
private Header[] buildHeadersArray(Map<String, String> headers)
{
List<BasicHeader> headersList = headers.entrySet().stream() //todo: dirty casting
.map(headerEntry -> new BasicHeader(headerEntry.getKey(), headerEntry.getValue()))
.collect(Collectors.toList());
Header[] headersArray = new Header[headersList.size()];
return headersList.toArray(headersArray);
} }
/* @Override
public TaskResponse getTaskResponse(User user, String path, ContainerRequestContext context) throws IOException public TaskResponse getTaskResponse(TaskRequestContext taskRequestContext) throws IOException
{ {
String kynHeaderValue = context.getHeaderString(KYN_HEADER_NAME); String proxiedUrl = getTaskUrl() + taskRequestContext.getPath();
CloseableHttpResponse response = proxyRequest(url, user, kynHeaderValue); CloseableHttpResponse response = proxyRequest(proxiedUrl, taskRequestContext);
String text = StreamUtils.readStream(response.getEntity().getContent()); String text = StreamUtils.readStream(response.getEntity().getContent());
Header kynHeader = response.getFirstHeader(KYN_HEADER_NAME); return new TaskResponse(text, buildHeadersMap(response.getAllHeaders()));
return new TaskResponse(text, kynHeader != null ? kynHeader.getValue() : null); //todo: needs refactorig
} }
*/
public String getUrl() public String getTaskUrl()
{ {
return url; return url;
} }
...@@ -63,12 +74,23 @@ public class WebTask extends Task ...@@ -63,12 +74,23 @@ public class WebTask extends Task
this.url = url; this.url = url;
} }
private CloseableHttpResponse proxyRequest(String url, User user, String kynHeaderValue) throws IOException private CloseableHttpResponse proxyRequest(String url, TaskRequestContext taskRequestContext) throws IOException
{ {
CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpget = new HttpGet(url);
httpget.setHeader("CTF-User", user.getName()); //todo: is it necessary? HttpMethod httpMethod = taskRequestContext.getHttpMethod();
httpget.setHeader("KYN_2016", kynHeaderValue); //todo: move to configuration if (httpMethod.equals(HttpMethod.GET)) {
return httpClient.execute(httpget); HttpGet httpget = new HttpGet(url);
httpget.setHeaders(buildHeadersArray(taskRequestContext.getHeaders()));
return httpClient.execute(httpget);
} else if (httpMethod.equals(HttpMethod.POST)) {
HttpPost httpPost = new HttpPost(url);
httpPost.setHeaders(buildHeadersArray(taskRequestContext.getHeaders()));
httpPost.setEntity(new ByteArrayEntity(taskRequestContext.getBody().getBytes("UTF-8")));
return httpClient.execute(httpPost);
} else {
throw new IllegalStateException("Invalid http method");
}
} }
} }
package com.telephoners.krakyournet.ctf.repositories; package com.telephoners.krakyournet.ctf.repositories;
import com.telephoners.krakyournet.ctf.beans.Flag;
import com.telephoners.krakyournet.ctf.beans.Solution; import com.telephoners.krakyournet.ctf.beans.Solution;
import com.telephoners.krakyournet.ctf.beans.Team; import com.telephoners.krakyournet.ctf.beans.Team;
import com.telephoners.krakyournet.ctf.beans.tasks.Task; import com.telephoners.krakyournet.ctf.beans.tasks.Task;
...@@ -26,7 +27,7 @@ public class SolutionsRepository extends Repository<Solution> ...@@ -26,7 +27,7 @@ public class SolutionsRepository extends Repository<Solution>
this.tasksRepository = tasksRepository; this.tasksRepository = tasksRepository;
} }
public Map<Integer, List<String>> getTeamSolutions(Team team) public Map<Integer, List<Flag>> getTeamSolutions(Team team)
{ {
//todo: do not identify team by name? conflict in team ids? //todo: do not identify team by name? conflict in team ids?
return datastore.createQuery(Solution.class) return datastore.createQuery(Solution.class)
...@@ -45,7 +46,7 @@ public class SolutionsRepository extends Repository<Solution> ...@@ -45,7 +46,7 @@ public class SolutionsRepository extends Repository<Solution>
.collect(Collectors.toMap( .collect(Collectors.toMap(
taskSolutions -> taskSolutions.getKey().getLevel(), taskSolutions -> taskSolutions.getKey().getLevel(),
taskSolutions -> taskSolutions.getValue().stream() taskSolutions -> taskSolutions.getValue().stream()
.map(solution -> solution.getFlag().getDescription()).collect(Collectors.toList()) .map(Solution::getFlag).collect(Collectors.toList())
)); ));
} }
...@@ -59,10 +60,10 @@ public class SolutionsRepository extends Repository<Solution> ...@@ -59,10 +60,10 @@ public class SolutionsRepository extends Repository<Solution>
public List<Integer> getCompletedTasks(Team team) public List<Integer> getCompletedTasks(Team team)
{ {
Map<Integer, List<String>> teamSolutions = getTeamSolutions(team); Map<Integer, List<Flag>> teamSolutions = getTeamSolutions(team);
return tasksRepository.getAll().stream() return tasksRepository.getAll().stream()
.filter(task -> { .filter(task -> {
List<String> teamTaskSolutions = teamSolutions.get(task.getLevel()); List<Flag> teamTaskSolutions = teamSolutions.get(task.getLevel());
return teamTaskSolutions != null && teamTaskSolutions.size() == task.getFlags().size(); return teamTaskSolutions != null && teamTaskSolutions.size() == task.getFlags().size();
}) })
.map(Task::getLevel) .map(Task::getLevel)
......
...@@ -76,7 +76,7 @@ public class SolutionsResource ...@@ -76,7 +76,7 @@ public class SolutionsResource
@GET @GET
@Path("/all") @Path("/all")
public Map<String, Map<Integer, List<String>>> getTeamsSolutions() public Map<String, Map<Integer, List<Flag>>> getTeamsSolutions()
{ {
return teamsRepository.getAll() return teamsRepository.getAll()
.stream() .stream()
......
...@@ -3,12 +3,10 @@ package com.telephoners.krakyournet.ctf.resources; ...@@ -3,12 +3,10 @@ package com.telephoners.krakyournet.ctf.resources;
import com.telephoners.krakyournet.ctf.beans.User; import com.telephoners.krakyournet.ctf.beans.User;
import com.telephoners.krakyournet.ctf.beans.tasks.Task; import com.telephoners.krakyournet.ctf.beans.tasks.Task;
import com.telephoners.krakyournet.ctf.beans.tasks.TaskRequestContext; import com.telephoners.krakyournet.ctf.beans.tasks.TaskRequestContext;
import com.telephoners.krakyournet.ctf.beans.tasks.TaskRequestContextBuilder;
import com.telephoners.krakyournet.ctf.beans.tasks.TaskResponse; import com.telephoners.krakyournet.ctf.beans.tasks.TaskResponse;
import com.telephoners.krakyournet.ctf.core.ApplicationConfiguration;
import com.telephoners.krakyournet.ctf.helpers.StreamUtils;
import com.telephoners.krakyournet.ctf.repositories.TasksRepository; import com.telephoners.krakyournet.ctf.repositories.TasksRepository;
import io.dropwizard.auth.Auth; import io.dropwizard.auth.Auth;
import org.glassfish.jersey.server.ContainerRequest;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
...@@ -18,109 +16,64 @@ import javax.ws.rs.Path; ...@@ -18,109 +16,64 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Singleton @Singleton
@Path(value = "/task") @Path(value = "/task")
public class TaskResource public class TaskResource
{ {
private final ApplicationConfiguration applicationConfiguration;
private final TasksRepository tasksRepository; private final TasksRepository tasksRepository;
private final TaskRequestContextBuilder taskRequestContextBuilder;
@Inject @Inject
public TaskResource(ApplicationConfiguration applicationConfiguration, TasksRepository tasksRepository) public TaskResource(TasksRepository tasksRepository, TaskRequestContextBuilder taskRequestContextBuilder)
{ {
this.applicationConfiguration = applicationConfiguration;
this.tasksRepository = tasksRepository; this.tasksRepository = tasksRepository;
this.taskRequestContextBuilder = taskRequestContextBuilder;
} }
//todo: name private Response buildResponse(TaskResponse taskResponse)
private TaskResponse getTaskResponse(int taskLevel, TaskRequestContext taskRequestContext) throws IOException
{ {
Task task = tasksRepository.getByLevel(taskLevel); Response.ResponseBuilder responseBuilder = Response.ok();
return task.getTaskResponse(taskRequestContext); responseBuilder.entity(taskResponse.getText());
taskResponse.getHeaders()
.entrySet()
.stream()
.forEach(headerEntry -> {
responseBuilder.header(headerEntry.getKey(), headerEntry.getValue());
});
return responseBuilder.build();
} }
private Map<String, String> extractProxiedHeaders(MultivaluedMap<String, String> headers) { private Response handleRequest(User user,
Set<String> proxiedHeaders = applicationConfiguration.getProxiedHeaders(); int taskLevel,
return headers.entrySet() String path,
.stream() ContainerRequestContext containerRequestContext) throws IOException
.filter(header -> proxiedHeaders.contains(header.getKey())) {
.collect(Collectors.toMap( Task task = tasksRepository.getByLevel(taskLevel);
Map.Entry::getKey, TaskRequestContext taskRequestContext = taskRequestContextBuilder.from(user, path, containerRequestContext);
entry -> entry.getValue().get(0) //todo: check return buildResponse(task.getTaskResponse(taskRequestContext));
));
} }
@Path("{task_level}/{path: .*}") @Path("{task_level}/{path: .*}")
@GET @GET
public Response getTaskGet(@Auth User user, public Response getTaskGet(@Auth User user,
final @PathParam("task_level") int taskLevel, final @PathParam("task_level") int taskLevel,
final @PathParam("path") String path, final @PathParam("path") String path,
@Context ContainerRequestContext containerRequestContext) throws IOException @Context ContainerRequestContext containerRequestContext) throws IOException
{ {
String fullPath = path; return handleRequest(user, taskLevel, path, containerRequestContext);
String query = ((ContainerRequest)containerRequestContext).getRequestUri().getQuery();
if(query != null) {
fullPath += query;
}
Map<String, String> headers = extractProxiedHeaders(containerRequestContext.getHeaders());//todo: inline
TaskRequestContext taskRequestContext = new TaskRequestContext()
.withHttpMethod("POST")
.withUser(user)
.withPath(fullPath)
.withHeaders(headers);
TaskResponse taskResponse = getTaskResponse(taskLevel, taskRequestContext);
Response.ResponseBuilder responseBuilder = Response.ok()
.entity(taskResponse.getText());
taskResponse.getHeaders().entrySet()
.stream()
.forEach(headerEntry -> responseBuilder.header(headerEntry.getKey(), headerEntry.getValue()));
return responseBuilder.build();
} }
@Path("{task_level}/{path: .*}") @Path("{task_level}/{path: .*}")
@POST @POST
public Response getTaskPost(@Auth User user, public Response getTaskPost(@Auth User user,
final @PathParam("task_level") int taskLevel, final @PathParam("task_level") int taskLevel,
final @PathParam("path") String path, final @PathParam("path") String path,
@Context ContainerRequestContext containerRequestContext) throws IOException @Context ContainerRequestContext containerRequestContext) throws IOException
{ {
String fullPath = path; return handleRequest(user, taskLevel, path, containerRequestContext);
String query = ((ContainerRequest)containerRequestContext).getRequestUri().getQuery();
if(query != null) {
fullPath += query;
}
String body = StreamUtils.readStream(containerRequestContext.getEntityStream());
//todo: TaskContextFrom
Map<String, String> headers = extractProxiedHeaders(containerRequestContext.getHeaders());//todo: inline
TaskRequestContext taskRequestContext = new TaskRequestContext()
.withHttpMethod("POST")
.withUser(user)
.withPath(fullPath)
.withBody(body)
.withHeaders(headers);
TaskResponse taskResponse = getTaskResponse(taskLevel, taskRequestContext);
Response.ResponseBuilder responseBuilder = Response.ok()
.entity(taskResponse.getText());
taskResponse.getHeaders().entrySet()
.stream()
.forEach(headerEntry -> responseBuilder.header(headerEntry.getKey(), headerEntry.getValue()));
return responseBuilder.build();
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment