mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-01-24 14:24:47 +08:00
more progress on cockroach
Signed-off-by: MiniDigger <admin@benndorf.dev>
This commit is contained in:
parent
4d04a854bb
commit
b4aff65770
@ -13,7 +13,7 @@ services:
|
||||
volumes:
|
||||
- db_data:/var/lib/postgresql/data
|
||||
cockroach:
|
||||
image: cockroachdb/cockroach
|
||||
image: cockroachdb/cockroach:latest-v21.2
|
||||
ports:
|
||||
- "26257:26257"
|
||||
- "26000:8080"
|
||||
|
@ -3,7 +3,7 @@
|
||||
<v-card>
|
||||
<v-card-title v-text="$t('organization.new.title')" />
|
||||
<v-card-subtitle>{{ $t('organization.new.text') }}</v-card-subtitle>
|
||||
<template v-if="currentUser.headerData.organizationCount < 1">
|
||||
<template v-if="currentUser.headerData.organizationCount < validations.maxOrgCount">
|
||||
<v-card-text>
|
||||
<v-form v-model="validForm">
|
||||
<v-text-field
|
||||
|
@ -3,15 +3,20 @@ package io.papermc.hangar.db.customtypes;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.postgresql.util.PGobject;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public class JSONB extends PGobject {
|
||||
|
||||
private static final String TYPE_STRING = "jsonb";
|
||||
|
||||
private transient JsonNode json;
|
||||
private transient Map<String, String> map;
|
||||
|
||||
public JSONB(String value) {
|
||||
setType(TYPE_STRING);
|
||||
@ -19,6 +24,16 @@ public class JSONB extends PGobject {
|
||||
parseJson();
|
||||
}
|
||||
|
||||
public JSONB(Object value) {
|
||||
setType(TYPE_STRING);
|
||||
try {
|
||||
this.value = new ObjectMapper().writeValueAsString(value);
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
parseJson();
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public JSONB(JsonNode json) {
|
||||
setType(TYPE_STRING);
|
||||
@ -35,6 +50,10 @@ public class JSONB extends PGobject {
|
||||
return json;
|
||||
}
|
||||
|
||||
public Map<String, String> getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
@ -44,6 +63,8 @@ public class JSONB extends PGobject {
|
||||
private void parseJson() {
|
||||
try {
|
||||
this.json = new ObjectMapper().readTree(value);
|
||||
this.map = new ObjectMapper().readValue(value, new TypeReference<Map<String, String>>() {
|
||||
});
|
||||
} catch (JsonProcessingException | ClassCastException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ public interface UsersDAO {
|
||||
" u.name," +
|
||||
" u.tagline," +
|
||||
" u.join_date," +
|
||||
" array(SELECT role_id FROM user_global_roles WHERE u.id = user_id) roles," +
|
||||
" array(SELECT role_id FROM user_global_roles WHERE u.id = user_id) AS roles," +
|
||||
" (SELECT count(*) FROM project_members_all pma WHERE pma.user_id = u.id) AS project_count," +
|
||||
" u.read_prompts," +
|
||||
" u.locked," +
|
||||
|
@ -35,7 +35,7 @@ public interface HangarStatsDAO {
|
||||
" sq.project_id," +
|
||||
" <if(includeVersionId)>sq.version_id,<endif>" +
|
||||
" count(DISTINCT sq.<if(withUserId)>user_id<else>address<endif>) FILTER (WHERE sq.processed \\<@ ARRAY[1])" +
|
||||
" FROM (SELECT date_trunc('DAY', d.created_at) AS day," +
|
||||
" FROM (SELECT date_trunc('DAY', d.created_at)::date AS day," +
|
||||
" d.project_id," +
|
||||
" <if(includeVersionId)>d.version_id,<endif>" +
|
||||
" <if(withUserId)>user_id<else>address<endif>," +
|
||||
|
@ -36,9 +36,9 @@ public interface HealthDAO {
|
||||
" p.visibility" +
|
||||
" FROM projects p " +
|
||||
" JOIN home_projects hp ON p.id = hp.id" +
|
||||
" WHERE hp.last_updated < (now() - make_interval(secs := <age>))" +
|
||||
" WHERE hp.last_updated < (now() - INTERVAL <age>)" +
|
||||
" ORDER BY p.created_at DESC")
|
||||
List<UnhealthyProject> getStaleProjects(@Define("age") long staleAgeSeconds);
|
||||
List<UnhealthyProject> getStaleProjects(@Define("age") String staleAgeSeconds);
|
||||
|
||||
@SqlQuery(" SELECT p.owner_name \"owner\"," +
|
||||
" p.slug," +
|
||||
|
@ -26,7 +26,7 @@ public interface JobsDAO {
|
||||
long countAwaitingJobs();
|
||||
|
||||
@SqlQuery("UPDATE jobs SET state = 'started', last_updated = now() WHERE id = (" +
|
||||
" SELECT id FROM jobs WHERE state = 'not_started' AND (retry_at IS NULL OR retry_at < now()) ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1" +
|
||||
" SELECT id FROM jobs WHERE state = 'not_started' AND (retry_at IS NULL OR retry_at < now()) ORDER BY id /*FOR UPDATE SKIP LOCKED*/ LIMIT 1" +
|
||||
") RETURNING *")
|
||||
JobTable fetchJob();
|
||||
|
||||
|
@ -13,7 +13,7 @@ import org.springframework.stereotype.Repository;
|
||||
public interface ApiKeyDAO {
|
||||
|
||||
@Timestamped
|
||||
@SqlUpdate("INSERT INTO api_keys (created_at, name, owner_id, token_identifier, token, raw_key_permissions) VALUES (:now, :name, :ownerId, :tokenIdentifier, crypt(:token, gen_salt('bf')), :permissions::bit(64))")
|
||||
@SqlUpdate("INSERT INTO api_keys (created_at, name, owner_id, token_identifier, token, raw_key_permissions) VALUES (:now, :name, :ownerId, :tokenIdentifier, :token, :permissions::bit(64))")
|
||||
void insert(@BindBean ApiKeyTable apiKeyTable);
|
||||
|
||||
@SqlUpdate("DELETE FROM api_keys WHERE name = :keyName AND owner_id = :userId")
|
||||
@ -22,8 +22,8 @@ public interface ApiKeyDAO {
|
||||
@SqlQuery("SELECT *, raw_key_permissions::bigint permissions FROM api_keys WHERE owner_id = :userId AND lower(name) = lower(:name)")
|
||||
ApiKeyTable getByUserAndName(long userId, String name);
|
||||
|
||||
@SqlQuery("SELECT *, raw_key_permissions::bigint permissions FROM api_keys WHERE token_identifier = :identifier AND token = crypt(:token, token)")
|
||||
ApiKeyTable findApiKey(String identifier, String token);
|
||||
@SqlQuery("SELECT *, raw_key_permissions::bigint permissions FROM api_keys WHERE token_identifier = :identifier AND token = :hashedToken")
|
||||
ApiKeyTable findApiKey(String identifier, String hashedToken);
|
||||
|
||||
@SqlQuery("SELECT *, raw_key_permissions::bigint permissions FROM api_keys WHERE owner_id = :userId AND token_identifier = :identifier")
|
||||
ApiKeyTable findApiKey(long userId, String identifier);
|
||||
|
@ -107,11 +107,11 @@ public interface ProjectsApiDAO {
|
||||
" JOIN projects p ON hp.id = p.id" +
|
||||
" WHERE true <filters>" + // Not sure how else to get here a single Where
|
||||
" <if(!seeHidden)> AND (hp.visibility = 0 <if(requesterId)>OR (:requesterId = ANY(hp.project_members) AND hp.visibility != 4)<endif>) <endif> " +
|
||||
" <if(orderBy)>ORDER BY :orderBy<endif> " +
|
||||
" ORDER BY <orderBy> " +
|
||||
" <offsetLimit>")
|
||||
@RegisterColumnMapper(PromotedVersionMapper.class)
|
||||
@DefineNamedBindings
|
||||
List<Project> getProjects(@Define boolean seeHidden, Long requesterId, String orderBy,
|
||||
List<Project> getProjects(@Define boolean seeHidden, Long requesterId, @Define String orderBy,
|
||||
@BindPagination RequestPagination pagination);
|
||||
|
||||
// This query can be shorter because it doesnt need all those column values as above does, just a single column for the amount of rows to be counted
|
||||
|
@ -18,27 +18,27 @@ public interface UsersApiDAO {
|
||||
|
||||
@RegisterConstructorMapper(ProjectCompact.class)
|
||||
@UseStringTemplateEngine
|
||||
@SqlQuery("SELECT p.created_at," +
|
||||
" p.name," +
|
||||
" p.owner_name \"owner\"," +
|
||||
" p.slug," +
|
||||
" p.views," +
|
||||
" p.downloads," +
|
||||
" p.recent_views," +
|
||||
" p.recent_downloads," +
|
||||
" p.stars," +
|
||||
" p.watchers," +
|
||||
" p.category," +
|
||||
" p.visibility" +
|
||||
@SqlQuery("SELECT hp.created_at," +
|
||||
" hp.name," +
|
||||
" hp.owner_name \"owner\"," +
|
||||
" hp.slug," +
|
||||
" hp.views," +
|
||||
" hp.downloads," +
|
||||
" hp.recent_views," +
|
||||
" hp.recent_downloads," +
|
||||
" hp.stars," +
|
||||
" hp.watchers," +
|
||||
" hp.category," +
|
||||
" hp.visibility" +
|
||||
" FROM users u " +
|
||||
" JOIN project_stars ps ON u.id = ps.user_id" +
|
||||
" JOIN home_projects p ON ps.project_id = p.id" +
|
||||
" JOIN home_projects hp ON ps.project_id = hp.id" +
|
||||
" WHERE " +
|
||||
" <if(!canSeeHidden)> (p.visibility = 0 OR p.visibility = 1" +
|
||||
" <if(userId)>OR (<userId> = ANY(p.project_members) AND p.visibility != 4)<endif>) AND<endif>" +
|
||||
" u.name = :user" +
|
||||
" ORDER BY :sortOrder LIMIT :limit OFFSET :offset")
|
||||
List<ProjectCompact> getUserStarred(String user, @Define boolean canSeeHidden, @Define Long userId, String sortOrder, long limit, long offset);
|
||||
" ORDER BY <sortOrder> LIMIT :limit OFFSET :offset")
|
||||
List<ProjectCompact> getUserStarred(String user, @Define boolean canSeeHidden, @Define Long userId, @Define String sortOrder, long limit, long offset);
|
||||
|
||||
@UseStringTemplateEngine
|
||||
@SqlQuery("SELECT count(*)" +
|
||||
@ -53,27 +53,27 @@ public interface UsersApiDAO {
|
||||
|
||||
@RegisterConstructorMapper(ProjectCompact.class)
|
||||
@UseStringTemplateEngine
|
||||
@SqlQuery("SELECT p.created_at," +
|
||||
" p.name," +
|
||||
" p.owner_name \"owner\"," +
|
||||
" p.slug," +
|
||||
" p.views," +
|
||||
" p.downloads," +
|
||||
" p.recent_views," +
|
||||
" p.recent_downloads," +
|
||||
" p.stars," +
|
||||
" p.watchers," +
|
||||
" p.category," +
|
||||
" p.visibility" +
|
||||
@SqlQuery("SELECT hp.created_at," +
|
||||
" hp.name," +
|
||||
" hp.owner_name \"owner\"," +
|
||||
" hp.slug," +
|
||||
" hp.views," +
|
||||
" hp.downloads," +
|
||||
" hp.recent_views," +
|
||||
" hp.recent_downloads," +
|
||||
" hp.stars," +
|
||||
" hp.watchers," +
|
||||
" hp.category," +
|
||||
" hp.visibility" +
|
||||
" FROM users u " +
|
||||
" JOIN project_watchers pw ON u.id = pw.user_id" +
|
||||
" JOIN home_projects p ON pw.project_id = p.id" +
|
||||
" JOIN home_projects hp ON pw.project_id = hp.id" +
|
||||
" WHERE " +
|
||||
" <if(!canSeeHidden)> (p.visibility = 0 OR p.visibility = 1" +
|
||||
" <if(userId)>OR (<userId> = ANY(p.project_members) AND p.visibility != 4)<endif>) AND<endif>" +
|
||||
" u.name = :user" +
|
||||
" ORDER BY :sortOrder LIMIT :limit OFFSET :offset")
|
||||
List<ProjectCompact> getUserWatching(String user, @Define boolean canSeeHidden, @Define Long userId, String sortOrder, long limit, long offset);
|
||||
" ORDER BY <sortOrder> LIMIT :limit OFFSET :offset")
|
||||
List<ProjectCompact> getUserWatching(String user, @Define boolean canSeeHidden, @Define Long userId, @Define String sortOrder, long limit, long offset);
|
||||
|
||||
@UseStringTemplateEngine
|
||||
@SqlQuery("SELECT count(*)" +
|
||||
@ -92,7 +92,7 @@ public interface UsersApiDAO {
|
||||
" u.tagline," +
|
||||
" u.join_date," +
|
||||
" u.locked," +
|
||||
" array(SELECT r.name FROM roles r JOIN user_global_roles ugr ON r.id = ugr.role_id WHERE u.id = ugr.user_id ORDER BY r.permission::BIGINT DESC) roles," +
|
||||
" array(SELECT r.name FROM roles r JOIN user_global_roles ugr ON r.id = ugr.role_id WHERE u.id = ugr.user_id ORDER BY r.permission::BIGINT DESC) AS roles," +
|
||||
" (SELECT count(*) FROM project_members_all pma WHERE pma.user_id = u.id) AS project_count" +
|
||||
" FROM users u" +
|
||||
" WHERE u.id IN " +
|
||||
@ -111,7 +111,7 @@ public interface UsersApiDAO {
|
||||
" u.tagline," +
|
||||
" u.join_date," +
|
||||
" u.locked," +
|
||||
" array_agg(r.name ORDER BY r.permission::BIGINT DESC) roles," +
|
||||
" array_agg(r.name ORDER BY r.permission::BIGINT DESC) AS roles," +
|
||||
" (SELECT count(*) FROM project_members_all pma WHERE pma.user_id = u.id) AS project_count" +
|
||||
" FROM users u" +
|
||||
" JOIN user_global_roles ugr ON u.id = ugr.user_id" +
|
||||
|
@ -6,6 +6,7 @@ import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
import io.papermc.hangar.db.customtypes.JSONB;
|
||||
import io.papermc.hangar.db.customtypes.JobState;
|
||||
import io.papermc.hangar.model.internal.job.JobType;
|
||||
|
||||
@ -17,9 +18,9 @@ public class JobTable extends Table {
|
||||
private final String lastErrorDescriptor;
|
||||
private final JobState state;
|
||||
private final JobType jobType;
|
||||
private final Map<String, String> jobProperties;
|
||||
private final JSONB jobProperties;
|
||||
|
||||
public JobTable(OffsetDateTime lastUpdated, OffsetDateTime retryAt, String lastError, String lastErrorDescriptor, JobState state, @EnumByName JobType jobType, Map<String, String> jobProperties) {
|
||||
public JobTable(OffsetDateTime lastUpdated, OffsetDateTime retryAt, String lastError, String lastErrorDescriptor, JobState state, @EnumByName JobType jobType, JSONB jobProperties) {
|
||||
this.lastUpdated = lastUpdated;
|
||||
this.retryAt = retryAt;
|
||||
this.lastError = lastError;
|
||||
@ -30,7 +31,7 @@ public class JobTable extends Table {
|
||||
}
|
||||
|
||||
@JdbiConstructor
|
||||
public JobTable(OffsetDateTime createdAt, long id, OffsetDateTime lastUpdated, OffsetDateTime retryAt, String lastError, String lastErrorDescriptor, JobState state, @EnumByName JobType jobType, Map<String, String> jobProperties) {
|
||||
public JobTable(OffsetDateTime createdAt, long id, OffsetDateTime lastUpdated, OffsetDateTime retryAt, String lastError, String lastErrorDescriptor, JobState state, @EnumByName JobType jobType, JSONB jobProperties) {
|
||||
super(createdAt, id);
|
||||
this.lastUpdated = lastUpdated;
|
||||
this.retryAt = retryAt;
|
||||
@ -65,7 +66,7 @@ public class JobTable extends Table {
|
||||
return jobType;
|
||||
}
|
||||
|
||||
public Map<String, String> getJobProperties() {
|
||||
public JSONB getJobProperties() {
|
||||
return jobProperties;
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@ public class ApiKeyTable extends Table implements Named {
|
||||
", ownerId=" + ownerId +
|
||||
", tokenIdentifier='" + tokenIdentifier + '\'' +
|
||||
", token='" + token + '\'' +
|
||||
", token='" + token + '\'' +
|
||||
", permissions=" + permissions +
|
||||
"} " + super.toString();
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class DeleteDiscourseTopicJob extends Job {
|
||||
public static DeleteDiscourseTopicJob loadFromTable(JobTable table) {
|
||||
DeleteDiscourseTopicJob job = new DeleteDiscourseTopicJob();
|
||||
job.fromTable(table);
|
||||
job.setJobProperties(table.getJobProperties());
|
||||
job.setJobProperties(table.getJobProperties().getMap());
|
||||
job.loadFromProperties();
|
||||
return job;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.papermc.hangar.model.internal.job;
|
||||
|
||||
import io.papermc.hangar.db.customtypes.JSONB;
|
||||
import io.papermc.hangar.db.customtypes.JobState;
|
||||
import io.papermc.hangar.model.Model;
|
||||
import io.papermc.hangar.model.db.JobTable;
|
||||
@ -104,12 +105,12 @@ public abstract class Job extends Model {
|
||||
this.lastErrorDescriptor = table.getLastErrorDescriptor();
|
||||
this.state = table.getState();
|
||||
this.jobType = table.getJobType();
|
||||
this.jobProperties = table.getJobProperties();
|
||||
this.jobProperties = table.getJobProperties().getMap();
|
||||
}
|
||||
|
||||
public JobTable toTable() {
|
||||
saveIntoProperties();
|
||||
return new JobTable(createdAt, -1, lastUpdated, retryAt, lastError, lastErrorDescriptor, state, jobType, jobProperties);
|
||||
return new JobTable(createdAt, -1, lastUpdated, retryAt, lastError, lastErrorDescriptor, state, jobType, new JSONB(jobProperties));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4,6 +4,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.papermc.hangar.db.customtypes.JSONB;
|
||||
import io.papermc.hangar.model.db.JobTable;
|
||||
|
||||
public class PostDiscourseReplyJob extends Job {
|
||||
@ -75,7 +76,7 @@ public class PostDiscourseReplyJob extends Job {
|
||||
public static PostDiscourseReplyJob loadFromTable(JobTable table) {
|
||||
PostDiscourseReplyJob job = new PostDiscourseReplyJob();
|
||||
job.fromTable(table);
|
||||
job.setJobProperties(table.getJobProperties());
|
||||
job.setJobProperties(table.getJobProperties().getMap());
|
||||
job.loadFromProperties();
|
||||
return job;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class UpdateDiscourseProjectTopicJob extends Job {
|
||||
public static UpdateDiscourseProjectTopicJob loadFromTable(JobTable table) {
|
||||
UpdateDiscourseProjectTopicJob job = new UpdateDiscourseProjectTopicJob();
|
||||
job.fromTable(table);
|
||||
job.setJobProperties(table.getJobProperties());
|
||||
job.setJobProperties(table.getJobProperties().getMap());
|
||||
job.loadFromProperties();
|
||||
return job;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class UpdateDiscourseVersionPostJob extends Job {
|
||||
public static UpdateDiscourseVersionPostJob loadFromTable(JobTable table) {
|
||||
UpdateDiscourseVersionPostJob job = new UpdateDiscourseVersionPostJob();
|
||||
job.fromTable(table);
|
||||
job.setJobProperties(table.getJobProperties());
|
||||
job.setJobProperties(table.getJobProperties().getMap());
|
||||
job.loadFromProperties();
|
||||
return job;
|
||||
}
|
||||
|
@ -12,11 +12,14 @@ import io.papermc.hangar.model.identified.UserIdentified;
|
||||
import io.papermc.hangar.model.internal.api.requests.CreateAPIKeyForm;
|
||||
import io.papermc.hangar.model.internal.logs.LogAction;
|
||||
import io.papermc.hangar.model.internal.logs.contexts.UserContext;
|
||||
import io.papermc.hangar.util.CryptoUtils;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
@ -54,7 +57,8 @@ public class APIKeyService extends HangarComponent {
|
||||
|
||||
String tokenIdentifier = UUID.randomUUID().toString();
|
||||
String token = UUID.randomUUID().toString();
|
||||
apiKeyDAO.insert(new ApiKeyTable(apiKeyForm.getName(), userIdentified.getUserId(), tokenIdentifier, token, keyPermission));
|
||||
String hashedToken = CryptoUtils.hmacSha256(config.security.getTokenSecret(), token.getBytes(StandardCharsets.UTF_8));
|
||||
apiKeyDAO.insert(new ApiKeyTable(apiKeyForm.getName(), userIdentified.getUserId(), tokenIdentifier, hashedToken, keyPermission));
|
||||
actionLogger.user(LogAction.USER_APIKEY_CREATED.create(UserContext.of(userIdentified.getUserId()), "Key Name: " + apiKeyForm.getName() + "<br>" + apiKeyForm.getPermissions().stream().map(NamedPermission::getFrontendName).collect(Collectors.joining(",<br>")), ""));
|
||||
return tokenIdentifier + "." + token;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.papermc.hangar.service.api;
|
||||
|
||||
import io.papermc.hangar.HangarComponent;
|
||||
import io.papermc.hangar.config.hangar.HangarSecurityConfig;
|
||||
import io.papermc.hangar.db.dao.internal.table.UserDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.auth.ApiKeyDAO;
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
@ -9,9 +10,12 @@ import io.papermc.hangar.model.db.UserTable;
|
||||
import io.papermc.hangar.model.db.auth.ApiKeyTable;
|
||||
import io.papermc.hangar.service.PermissionService;
|
||||
import io.papermc.hangar.service.TokenService;
|
||||
import io.papermc.hangar.util.CryptoUtils;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Service
|
||||
@ -39,7 +43,8 @@ public class APIAuthenticationService extends HangarComponent {
|
||||
}
|
||||
String identifier = apiKey.split("\\.")[0];
|
||||
String token = apiKey.split("\\.")[1];
|
||||
ApiKeyTable apiKeyTable = apiKeyDAO.findApiKey(identifier, token);
|
||||
String hashedToken = CryptoUtils.hmacSha256(config.security.getTokenSecret(), token.getBytes(StandardCharsets.UTF_8));
|
||||
ApiKeyTable apiKeyTable = apiKeyDAO.findApiKey(identifier, hashedToken);
|
||||
if (apiKeyTable == null) {
|
||||
throw new HangarApiException("No valid API Key found");
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public class HealthService extends HangarComponent {
|
||||
}
|
||||
|
||||
public List<UnhealthyProject> getStaleProjects() {
|
||||
return healthDAO.getStaleProjects(config.projects.getStaleAge().toSeconds());
|
||||
return healthDAO.getStaleProjects("'" + config.projects.getStaleAge().toSeconds() + " SECONDS'");
|
||||
}
|
||||
|
||||
public List<UnhealthyProject> getNonPublicProjects() {
|
||||
|
@ -39,6 +39,7 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@ -108,6 +109,9 @@ public class ProjectService extends HangarComponent {
|
||||
|
||||
public HangarProject getHangarProject(String author, String slug) {
|
||||
Pair<Long, Project> project = hangarProjectsDAO.getProject(author, slug, getHangarUserId());
|
||||
if (project == null) {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
ProjectOwner projectOwner = getProjectOwner(author);
|
||||
var members = hangarProjectsDAO.getProjectMembers(project.getLeft(), getHangarUserId(), permissionService.getProjectPermissions(getHangarUserId(), project.getLeft()).has(Permission.EditProjectSettings));
|
||||
String lastVisibilityChangeComment = "";
|
||||
@ -217,7 +221,8 @@ public class ProjectService extends HangarComponent {
|
||||
}
|
||||
|
||||
public void refreshHomeProjects() {
|
||||
hangarProjectsDAO.refreshHomeProjects();
|
||||
// hangarProjectsDAO.refreshHomeProjects();
|
||||
// TODO fix refreshHomeProjects: ERROR: cannot refresh view in an explicit transaction
|
||||
}
|
||||
|
||||
public List<UserTable> getProjectWatchers(long projectId) {
|
||||
|
@ -15,16 +15,21 @@ public class CryptoUtils {
|
||||
|
||||
private static final char[] hexArray = "0123456789abcdef".toCharArray();
|
||||
|
||||
public static byte[] hmac(String algo, byte[] secret, byte[] data) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
public static byte[] hmac(String algo, byte[] secret, byte[] data) {
|
||||
Preconditions.checkArgument(secret.length != 0, "empty secret");
|
||||
Preconditions.checkArgument(data.length != 0, "nothing to hash!");
|
||||
Mac hmac = Mac.getInstance(algo);
|
||||
SecretKeySpec keySpec = new SecretKeySpec(secret, algo);
|
||||
hmac.init(keySpec);
|
||||
return hmac.doFinal(data);
|
||||
try {
|
||||
Mac hmac = Mac.getInstance(algo);
|
||||
SecretKeySpec keySpec = new SecretKeySpec(secret, algo);
|
||||
hmac.init(keySpec);
|
||||
return hmac.doFinal(data);
|
||||
} catch (InvalidKeyException | NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String hmacSha256(String secret, byte[] data) throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
public static String hmacSha256(String secret, byte[] data) {
|
||||
return bytesToHex(hmac("HmacSHA256", secret.getBytes(StandardCharsets.UTF_8), data));
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,19 @@ spring:
|
||||
WRITE_DATES_AS_TIMESTAMPS: false
|
||||
date-format: com.fasterxml.jackson.databind.util.StdDateFormat
|
||||
|
||||
###############
|
||||
# Email Stuff #
|
||||
###############
|
||||
# mail:
|
||||
# host: smtp.gmail.com
|
||||
# username: username
|
||||
# password: password
|
||||
# properties:
|
||||
# mail.transport.protocol: smtp
|
||||
# mail.smtp.port: 587
|
||||
# mail.smtp.auth: true
|
||||
# mail.smtp.starttls.enable: true
|
||||
|
||||
#############
|
||||
# Fake User #
|
||||
#############
|
||||
@ -164,6 +177,7 @@ hangar:
|
||||
logging:
|
||||
level:
|
||||
root: INFO
|
||||
org.springframework: DEBUG
|
||||
org.springframework: INFO
|
||||
org.springframework.context.support.PostProcessorRegistrationDelegate: WARN
|
||||
io.papermc.hangar.service.internal.JobService: DEBUG
|
||||
io.papermc.hangar.config.WebConfig.LoggingInterceptor: DEBUG
|
||||
|
@ -152,7 +152,7 @@ CREATE TABLE project_pages
|
||||
);
|
||||
|
||||
CREATE INDEX page_slug_idx
|
||||
ON project_pages (slug);
|
||||
ON project_pages (lower(slug));
|
||||
|
||||
CREATE INDEX page_parent_id_idx
|
||||
ON project_pages (parent_id);
|
||||
@ -974,13 +974,15 @@ SELECT p.id,
|
||||
p.description,
|
||||
p.name,
|
||||
p.created_at,
|
||||
max(lv.created_at) AS last_updated--,--
|
||||
max(lv.created_at) AS last_updated,
|
||||
-- to_jsonb(ARRAY(SELECT jsonb_build_object('version_string', tags.version_string, 'tag_name', tags.tag_name,
|
||||
-- 'tag_version', tags.tag_version, 'tag_color',
|
||||
-- tags.tag_color) AS jsonb_build_object
|
||||
-- FROM tags
|
||||
-- WHERE tags.project_id = p.id
|
||||
-- LIMIT 5)) AS promoted_versions,
|
||||
--TODO fix homepage view
|
||||
ARRAY(SELECT 1 WHERE FALSE) AS promoted_versions,
|
||||
-- ((setweight((to_tsvector('english'::regconfig, p.name::text) ||
|
||||
-- to_tsvector('english'::regconfig, regexp_replace(p.name::text, '([a-z])([A-Z]+)'::text,
|
||||
-- '\1_\2'::text, 'g'::text))), 'A'::"char") ||
|
||||
@ -993,6 +995,8 @@ SELECT p.id,
|
||||
-- '\1_\2'::text,
|
||||
-- 'g'::text)),
|
||||
-- 'D'::"char") AS search_words
|
||||
-- TODO fix homepage view
|
||||
'DUM' AS search_words
|
||||
FROM projects p
|
||||
LEFT JOIN project_versions lv ON p.id = lv.project_id
|
||||
JOIN project_members_all pm ON p.id = pm.id
|
||||
|
@ -6,5 +6,5 @@ SELECT
|
||||
(SELECT count(*) FROM project_flags WHERE created_at::date <= day AND (created_at::date >= day OR resolved_at IS NULL)) flagsOpened,
|
||||
(SELECT count(*) FROM project_flags WHERE resolved_at::date = day) flagsClosed,
|
||||
day::date
|
||||
FROM (SELECT generate_series(:startDate, :endDate, INTERVAL '1 DAY') AS day) dates
|
||||
ORDER BY day
|
||||
FROM (SELECT generate_series(:startDate::timestamp, :endDate::timestamp, INTERVAL '1 DAY') AS day) dates
|
||||
ORDER BY day
|
||||
|
Loading…
Reference in New Issue
Block a user