Compare commits

...

2 Commits
2.2.0 ... 2.2.1

Author SHA1 Message Date
Anatoly Sablin
eb1326c56a Add unique id for the accepted table.
Add a little more logs.
2019-12-10 22:29:00 +03:00
Anatoly Sablin
10cdb4360e Fix homeserver verification with wildcards certificates.
Disable v2 by default.
Add migration to fix the accepted table (due to sqlite unable to change constraint, drop table and create again).
Fix displaying the expiration period of the new token.
Remove duplicated code.
Use v1 single lookup when receive the request with `none` algorithm and the only one argument.
Hide v2 endpoint if v2 API disabled.
2019-12-10 00:10:13 +03:00
11 changed files with 193 additions and 125 deletions

View File

@@ -7,7 +7,7 @@ Default values:
```.yaml ```.yaml
matrix: matrix:
v1: true # deprecated v1: true # deprecated
v2: true v2: false
``` ```
To disable change value to `false`. To disable change value to `false`.
@@ -19,8 +19,14 @@ matrix:
``` ```
NOTE: Riot Web version 1.5.5 and below checks the v1 for backward compatibility. NOTE: Riot Web version 1.5.5 and below checks the v1 for backward compatibility.
NOTE: v2 disabled by default in order to preserve backward compatibility.
## Terms ## Terms
###### Requires: No.
Administrator can omit terms configuration. In this case the terms checking will be disabled.
Example: Example:
```.yaml ```.yaml
policy: policy:
@@ -45,7 +51,7 @@ Where:
- `version` -- the terms version. - `version` -- the terms version.
- `lang` -- the term language. - `lang` -- the term language.
- `name` -- the name of the term. - `name` -- the name of the term.
- `url` -- the url of the term. - `url` -- the url of the term. Might be any url (i.e. from another host) for a html page.
- `regexp` -- regexp patterns for API which should be available only after accepting the terms. - `regexp` -- regexp patterns for API which should be available only after accepting the terms.
API will be checks for accepted terms only with authorization. API will be checks for accepted terms only with authorization.
@@ -72,6 +78,10 @@ There is only one exception: [`POST /_matrix/identity/v2/terms`](https://matrix.
Hashes and the pepper updates together according to the `rotationPolicy`. Hashes and the pepper updates together according to the `rotationPolicy`.
###### Requires: No.
In case the `none` algorithms ma1sd will be lookup using the v1 bulk API.
```.yaml ```.yaml
hashing: hashing:
enabled: true # enable or disable the hash lookup MSC2140 (default is false) enabled: true # enable or disable the hash lookup MSC2140 (default is false)

View File

@@ -22,7 +22,7 @@
matrix: matrix:
domain: '' domain: ''
v1: true # deprecated v1: true # deprecated
v2: true # MSC2140 API v2 v2: false # MSC2140 API v2. Disabled by default in order to preserve backward compatibility.
################ ################
@@ -115,16 +115,16 @@ threepid:
#### MSC2134 (hash lookup) #### MSC2134 (hash lookup)
hashing: #hashing:
enabled: false # enable or disable the hash lookup MSC2140 (default is false) # enabled: false # enable or disable the hash lookup MSC2140 (default is false)
pepperLength: 20 # length of the pepper value (default is 20) # pepperLength: 20 # length of the pepper value (default is 20)
rotationPolicy: per_requests # or `per_seconds` how often the hashes will be updating # rotationPolicy: per_requests # or `per_seconds` how often the hashes will be updating
hashStorageType: sql # or `in_memory` where the hashes will be stored # hashStorageType: sql # or `in_memory` where the hashes will be stored
algorithms: # algorithms:
- none # the same as v1 bulk lookup # - none # the same as v1 bulk lookup
- sha256 # hash the 3PID and pepper. # - sha256 # hash the 3PID and pepper.
delay: 2m # how often hashes will be updated if rotation policy = per_seconds (default is 10s) # delay: 2m # how often hashes will be updated if rotation policy = per_seconds (default is 10s)
requests: 10 # how many lookup requests will be performed before updating hashes if rotation policy = per_requests (default is 10) # requests: 10 # how many lookup requests will be performed before updating hashes if rotation policy = per_requests (default is 10)
### hash lookup for synapseSql provider. ### hash lookup for synapseSql provider.
# synapseSql: # synapseSql:
@@ -132,19 +132,19 @@ hashing:
# query: 'select user_id as mxid, medium, address from user_threepids' # query for retrive 3PIDs for hashes. # query: 'select user_id as mxid, medium, address from user_threepids' # query for retrive 3PIDs for hashes.
#### MSC2140 (Terms) #### MSC2140 (Terms)
policy: #policy:
policies: # policies:
term_name: # term name # term_name: # term name
version: 1.0 # version # version: 1.0 # version
terms: # terms:
en: # lang # en: # lang
name: term name en # localized name # name: term name en # localized name
url: https://ma1sd.host.tld/term_en.html # localized url # url: https://ma1sd.host.tld/term_en.html # localized url
fe: # lang # fe: # lang
name: term name fr # localized name # name: term name fr # localized name
url: https://ma1sd.host.tld/term_fr.html # localized url # url: https://ma1sd.host.tld/term_fr.html # localized url
regexp: # regexp:
- '/_matrix/identity/v2/account.*' # - '/_matrix/identity/v2/account.*'
- '/_matrix/identity/v2/hash_details' # - '/_matrix/identity/v2/hash_details'
- '/_matrix/identity/v2/lookup' # - '/_matrix/identity/v2/lookup'
#

View File

@@ -189,24 +189,33 @@ public class HttpMxisd {
} }
private void accountEndpoints(RoutingHandler routingHandler) { private void accountEndpoints(RoutingHandler routingHandler) {
MatrixConfig matrixConfig = m.getConfig().getMatrix();
if (matrixConfig.isV2()) {
routingHandler.post(AccountRegisterHandler.Path, SaneHandler.around(new AccountRegisterHandler(m.getAccMgr()))); routingHandler.post(AccountRegisterHandler.Path, SaneHandler.around(new AccountRegisterHandler(m.getAccMgr())));
wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.GET, sane(new AccountGetUserInfoHandler(m.getAccMgr())), wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.GET, sane(new AccountGetUserInfoHandler(m.getAccMgr())),
AccountGetUserInfoHandler.Path, true); AccountGetUserInfoHandler.Path, true);
wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.GET, sane(new AccountLogoutHandler(m.getAccMgr())), wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.GET, sane(new AccountLogoutHandler(m.getAccMgr())),
AccountLogoutHandler.Path, true); AccountLogoutHandler.Path, true);
} }
}
private void termsEndpoints(RoutingHandler routingHandler) { private void termsEndpoints(RoutingHandler routingHandler) {
MatrixConfig matrixConfig = m.getConfig().getMatrix();
if (matrixConfig.isV2()) {
routingHandler.get(GetTermsHandler.PATH, new GetTermsHandler(m.getConfig().getPolicy())); routingHandler.get(GetTermsHandler.PATH, new GetTermsHandler(m.getConfig().getPolicy()));
routingHandler.post(AcceptTermsHandler.PATH, sane(new AcceptTermsHandler(m.getAccMgr()))); routingHandler.post(AcceptTermsHandler.PATH, sane(new AcceptTermsHandler(m.getAccMgr())));
} }
}
private void hashEndpoints(RoutingHandler routingHandler) { private void hashEndpoints(RoutingHandler routingHandler) {
MatrixConfig matrixConfig = m.getConfig().getMatrix();
if (matrixConfig.isV2()) {
wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.GET, sane(new HashDetailsHandler(m.getHashManager())), wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.GET, sane(new HashDetailsHandler(m.getHashManager())),
HashDetailsHandler.PATH, true); HashDetailsHandler.PATH, true);
wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.POST, wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.POST,
sane(new HashLookupHandler(m.getIdentity(), m.getHashManager())), HashLookupHandler.Path, true); sane(new HashLookupHandler(m.getIdentity(), m.getHashManager())), HashLookupHandler.Path, true);
} }
}
private void addEndpoints(RoutingHandler routingHandler, HttpString method, boolean useAuthorization, ApiHandler... handlers) { private void addEndpoints(RoutingHandler routingHandler, HttpString method, boolean useAuthorization, ApiHandler... handlers) {
for (ApiHandler handler : handlers) { for (ApiHandler handler : handlers) {

View File

@@ -10,6 +10,7 @@ import io.kamax.mxisd.exception.BadRequestException;
import io.kamax.mxisd.exception.InvalidCredentialsException; import io.kamax.mxisd.exception.InvalidCredentialsException;
import io.kamax.mxisd.exception.NotFoundException; import io.kamax.mxisd.exception.NotFoundException;
import io.kamax.mxisd.matrix.HomeserverFederationResolver; import io.kamax.mxisd.matrix.HomeserverFederationResolver;
import io.kamax.mxisd.matrix.HomeserverVerifier;
import io.kamax.mxisd.storage.IStorage; import io.kamax.mxisd.storage.IStorage;
import io.kamax.mxisd.storage.ormlite.dao.AccountDao; import io.kamax.mxisd.storage.ormlite.dao.AccountDao;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
@@ -22,18 +23,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.security.cert.Certificate;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
public class AccountManager { public class AccountManager {
@@ -80,7 +73,7 @@ public class AccountManager {
homeserverURL + "/_matrix/federation/v1/openid/userinfo?access_token=" + openIdToken.getAccessToken()); homeserverURL + "/_matrix/federation/v1/openid/userinfo?access_token=" + openIdToken.getAccessToken());
String userId; String userId;
try (CloseableHttpClient httpClient = HttpClients.custom() try (CloseableHttpClient httpClient = HttpClients.custom()
.setSSLHostnameVerifier(new MatrixHostnameVerifier(homeserverTarget.getDomain())).build()) { .setSSLHostnameVerifier(new HomeserverVerifier(homeserverTarget.getDomain())).build()) {
try (CloseableHttpResponse response = httpClient.execute(getUserInfo)) { try (CloseableHttpResponse response = httpClient.execute(getUserInfo)) {
int statusCode = response.getStatusLine().getStatusCode(); int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) { if (statusCode == HttpStatus.SC_OK) {
@@ -170,74 +163,4 @@ public class AccountManager {
public MatrixConfig getMatrixConfig() { public MatrixConfig getMatrixConfig() {
return matrixConfig; return matrixConfig;
} }
public static class MatrixHostnameVerifier implements HostnameVerifier {
private static final String ALT_DNS_NAME_TYPE = "2";
private static final String ALT_IP_ADDRESS_TYPE = "7";
private final String matrixHostname;
public MatrixHostnameVerifier(String matrixHostname) {
this.matrixHostname = matrixHostname;
}
@Override
public boolean verify(String hostname, SSLSession session) {
try {
Certificate peerCertificate = session.getPeerCertificates()[0];
if (peerCertificate instanceof X509Certificate) {
X509Certificate x509Certificate = (X509Certificate) peerCertificate;
if (x509Certificate.getSubjectAlternativeNames() == null) {
return false;
}
for (String altSubjectName : getAltSubjectNames(x509Certificate)) {
if (match(altSubjectName)) {
return true;
}
}
}
} catch (SSLPeerUnverifiedException | CertificateParsingException e) {
LOGGER.error("Unable to check remote host", e);
return false;
}
return false;
}
private List<String> getAltSubjectNames(X509Certificate x509Certificate) {
List<String> subjectNames = new ArrayList<>();
try {
for (List<?> subjectAlternativeNames : x509Certificate.getSubjectAlternativeNames()) {
if (subjectAlternativeNames == null
|| subjectAlternativeNames.size() < 2
|| subjectAlternativeNames.get(0) == null
|| subjectAlternativeNames.get(1) == null) {
continue;
}
String subjectType = subjectAlternativeNames.get(0).toString();
switch (subjectType) {
case ALT_DNS_NAME_TYPE:
case ALT_IP_ADDRESS_TYPE:
subjectNames.add(subjectAlternativeNames.get(1).toString());
break;
default:
LOGGER.trace("Unusable subject type: " + subjectType);
}
}
} catch (CertificateParsingException e) {
LOGGER.error("Unable to parse the certificate", e);
return Collections.emptyList();
}
return subjectNames;
}
private boolean match(String altSubjectName) {
if (altSubjectName.startsWith("*.")) {
return altSubjectName.toLowerCase().endsWith(matrixHostname.toLowerCase());
} else {
return matrixHostname.equalsIgnoreCase(altSubjectName);
}
}
}
} }

View File

@@ -64,7 +64,7 @@ public class MatrixConfig {
private String domain; private String domain;
private Identity identity = new Identity(); private Identity identity = new Identity();
private boolean v1 = true; private boolean v1 = true;
private boolean v2 = true; private boolean v2 = false;
public String getDomain() { public String getDomain() {
return domain; return domain;

View File

@@ -48,7 +48,7 @@ public class AccountRegisterHandler extends BasicHttpHandler {
if (LOGGER.isInfoEnabled()) { if (LOGGER.isInfoEnabled()) {
LOGGER.info("Registration from domain: {}, expired at {}", openIdToken.getMatrixServerName(), LOGGER.info("Registration from domain: {}, expired at {}", openIdToken.getMatrixServerName(),
new Date(openIdToken.getExpiresIn())); new Date(System.currentTimeMillis() + openIdToken.getExpiresIn()));
} }
String token = accountManager.register(openIdToken); String token = accountManager.register(openIdToken);

View File

@@ -31,6 +31,8 @@ import io.kamax.mxisd.http.undertow.handler.ApiHandler;
import io.kamax.mxisd.http.undertow.handler.identity.share.LookupHandler; import io.kamax.mxisd.http.undertow.handler.identity.share.LookupHandler;
import io.kamax.mxisd.lookup.BulkLookupRequest; import io.kamax.mxisd.lookup.BulkLookupRequest;
import io.kamax.mxisd.lookup.HashLookupRequest; import io.kamax.mxisd.lookup.HashLookupRequest;
import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.strategy.LookupStrategy; import io.kamax.mxisd.lookup.strategy.LookupStrategy;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
@@ -40,6 +42,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
public class HashLookupHandler extends LookupHandler implements ApiHandler { public class HashLookupHandler extends LookupHandler implements ApiHandler {
@@ -89,6 +92,18 @@ public class HashLookupHandler extends LookupHandler implements ApiHandler {
throw new InvalidParamException(); throw new InvalidParamException();
} }
ClientHashLookupAnswer answer = null;
if (input.getAddresses() != null && input.getAddresses().size() > 0) {
if (input.getAddresses().size() == 1) {
answer = noneSingleLookup(request, input);
} else {
answer = noneBulkLookup(request, input);
}
}
respondJson(exchange, answer != null ? answer : new ClientHashLookupAnswer());
}
private ClientHashLookupAnswer noneBulkLookup(HashLookupRequest request, ClientHashLookupRequest input) throws Exception {
BulkLookupRequest bulkLookupRequest = new BulkLookupRequest(); BulkLookupRequest bulkLookupRequest = new BulkLookupRequest();
List<ThreePidMapping> mappings = new ArrayList<>(); List<ThreePidMapping> mappings = new ArrayList<>();
for (String address : input.getAddresses()) { for (String address : input.getAddresses()) {
@@ -107,7 +122,26 @@ public class HashLookupHandler extends LookupHandler implements ApiHandler {
} }
log.info("Finished bulk lookup request from {}", request.getRequester()); log.info("Finished bulk lookup request from {}", request.getRequester());
respondJson(exchange, answer); return answer;
}
private ClientHashLookupAnswer noneSingleLookup(HashLookupRequest request, ClientHashLookupRequest input) {
SingleLookupRequest singleLookupRequest = new SingleLookupRequest();
String address = input.getAddresses().get(0);
String[] parts = address.split(" ");
singleLookupRequest.setThreePid(parts[0]);
singleLookupRequest.setType(parts[1]);
ClientHashLookupAnswer answer = new ClientHashLookupAnswer();
Optional<SingleLookupReply> singleLookupReply = strategy.find(singleLookupRequest);
if (singleLookupReply.isPresent()) {
SingleLookupReply reply = singleLookupReply.get();
answer.getMappings().put(address, reply.getMxid().toString());
}
log.info("Finished single lookup request from {}", request.getRequester());
return answer;
} }
private void sha256Algorithm(HttpServerExchange exchange, HashLookupRequest request, ClientHashLookupRequest input) { private void sha256Algorithm(HttpServerExchange exchange, HashLookupRequest request, ClientHashLookupRequest input) {

View File

@@ -77,7 +77,8 @@ public class HomeserverVerifier implements HostnameVerifier {
private boolean match(String altSubjectName) { private boolean match(String altSubjectName) {
if (altSubjectName.startsWith("*.")) { if (altSubjectName.startsWith("*.")) {
return altSubjectName.toLowerCase().endsWith(matrixHostname.toLowerCase()); String subjectNameWithoutMask = altSubjectName.substring(1); // remove wildcard
return matrixHostname.toLowerCase().endsWith(subjectNameWithoutMask.toLowerCase());
} else { } else {
return matrixHostname.equalsIgnoreCase(altSubjectName); return matrixHostname.equalsIgnoreCase(altSubjectName);
} }

View File

@@ -39,6 +39,7 @@ import io.kamax.mxisd.storage.IStorage;
import io.kamax.mxisd.storage.dao.IThreePidSessionDao; import io.kamax.mxisd.storage.dao.IThreePidSessionDao;
import io.kamax.mxisd.storage.ormlite.dao.ASTransactionDao; import io.kamax.mxisd.storage.ormlite.dao.ASTransactionDao;
import io.kamax.mxisd.storage.ormlite.dao.AccountDao; import io.kamax.mxisd.storage.ormlite.dao.AccountDao;
import io.kamax.mxisd.storage.ormlite.dao.ChangelogDao;
import io.kamax.mxisd.storage.ormlite.dao.HashDao; import io.kamax.mxisd.storage.ormlite.dao.HashDao;
import io.kamax.mxisd.storage.ormlite.dao.HistoricalThreePidInviteIO; import io.kamax.mxisd.storage.ormlite.dao.HistoricalThreePidInviteIO;
import io.kamax.mxisd.storage.ormlite.dao.AcceptedDao; import io.kamax.mxisd.storage.ormlite.dao.AcceptedDao;
@@ -46,12 +47,15 @@ import io.kamax.mxisd.storage.ormlite.dao.ThreePidInviteIO;
import io.kamax.mxisd.storage.ormlite.dao.ThreePidSessionDao; import io.kamax.mxisd.storage.ormlite.dao.ThreePidSessionDao;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@@ -59,6 +63,8 @@ import java.util.stream.Collectors;
public class OrmLiteSqlStorage implements IStorage { public class OrmLiteSqlStorage implements IStorage {
private static final Logger LOGGER = LoggerFactory.getLogger(OrmLiteSqlStorage.class);
@FunctionalInterface @FunctionalInterface
private interface Getter<T> { private interface Getter<T> {
@@ -73,13 +79,18 @@ public class OrmLiteSqlStorage implements IStorage {
} }
public static class Migrations {
public static final String FIX_ACCEPTED_DAO = "2019_12_09__2254__fix_accepted_dao";
}
private Dao<ThreePidInviteIO, String> invDao; private Dao<ThreePidInviteIO, String> invDao;
private Dao<HistoricalThreePidInviteIO, String> expInvDao; private Dao<HistoricalThreePidInviteIO, String> expInvDao;
private Dao<ThreePidSessionDao, String> sessionDao; private Dao<ThreePidSessionDao, String> sessionDao;
private Dao<ASTransactionDao, String> asTxnDao; private Dao<ASTransactionDao, String> asTxnDao;
private Dao<AccountDao, String> accountDao; private Dao<AccountDao, String> accountDao;
private Dao<AcceptedDao, String> acceptedDao; private Dao<AcceptedDao, Long> acceptedDao;
private Dao<HashDao, String> hashDao; private Dao<HashDao, String> hashDao;
private Dao<ChangelogDao, String> changelogDao;
public OrmLiteSqlStorage(MxisdConfig cfg) { public OrmLiteSqlStorage(MxisdConfig cfg) {
this(cfg.getStorage().getBackend(), cfg.getStorage().getProvider().getSqlite().getDatabase()); this(cfg.getStorage().getBackend(), cfg.getStorage().getProvider().getSqlite().getDatabase());
@@ -96,6 +107,7 @@ public class OrmLiteSqlStorage implements IStorage {
withCatcher(() -> { withCatcher(() -> {
ConnectionSource connPool = new JdbcConnectionSource("jdbc:" + backend + ":" + path); ConnectionSource connPool = new JdbcConnectionSource("jdbc:" + backend + ":" + path);
changelogDao = createDaoAndTable(connPool, ChangelogDao.class);
invDao = createDaoAndTable(connPool, ThreePidInviteIO.class); invDao = createDaoAndTable(connPool, ThreePidInviteIO.class);
expInvDao = createDaoAndTable(connPool, HistoricalThreePidInviteIO.class); expInvDao = createDaoAndTable(connPool, HistoricalThreePidInviteIO.class);
sessionDao = createDaoAndTable(connPool, ThreePidSessionDao.class); sessionDao = createDaoAndTable(connPool, ThreePidSessionDao.class);
@@ -103,10 +115,26 @@ public class OrmLiteSqlStorage implements IStorage {
accountDao = createDaoAndTable(connPool, AccountDao.class); accountDao = createDaoAndTable(connPool, AccountDao.class);
acceptedDao = createDaoAndTable(connPool, AcceptedDao.class); acceptedDao = createDaoAndTable(connPool, AcceptedDao.class);
hashDao = createDaoAndTable(connPool, HashDao.class); hashDao = createDaoAndTable(connPool, HashDao.class);
runMigration(connPool);
}); });
} }
private void runMigration(ConnectionSource connPol) throws SQLException {
ChangelogDao fixAcceptedDao = changelogDao.queryForId(Migrations.FIX_ACCEPTED_DAO);
if (fixAcceptedDao == null) {
fixAcceptedDao(connPol);
changelogDao.create(new ChangelogDao(Migrations.FIX_ACCEPTED_DAO, new Date(), "Recreate the accepted table."));
}
}
private void fixAcceptedDao(ConnectionSource connPool) throws SQLException {
LOGGER.info("Migration: {}", Migrations.FIX_ACCEPTED_DAO);
TableUtils.dropTable(acceptedDao, true);
TableUtils.createTableIfNotExists(connPool, AcceptedDao.class);
}
private <V, K> Dao<V, K> createDaoAndTable(ConnectionSource connPool, Class<V> c) throws SQLException { private <V, K> Dao<V, K> createDaoAndTable(ConnectionSource connPool, Class<V> c) throws SQLException {
LOGGER.info("Create the dao: {}", c.getSimpleName());
Dao<V, K> dao = DaoManager.createDao(connPool, c); Dao<V, K> dao = DaoManager.createDao(connPool, c);
TableUtils.createTableIfNotExists(connPool, c); TableUtils.createTableIfNotExists(connPool, c);
return dao; return dao;

View File

@@ -26,7 +26,10 @@ import com.j256.ormlite.table.DatabaseTable;
@DatabaseTable(tableName = "accepted") @DatabaseTable(tableName = "accepted")
public class AcceptedDao { public class AcceptedDao {
@DatabaseField(canBeNull = false, id = true) @DatabaseField(generatedId = true)
private Long id;
@DatabaseField(canBeNull = false)
private String url; private String url;
@DatabaseField(canBeNull = false) @DatabaseField(canBeNull = false)
@@ -45,6 +48,14 @@ public class AcceptedDao {
this.acceptedAt = acceptedAt; this.acceptedAt = acceptedAt;
} }
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUrl() { public String getUrl() {
return url; return url;
} }

View File

@@ -0,0 +1,52 @@
package io.kamax.mxisd.storage.ormlite.dao;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import java.util.Date;
@DatabaseTable(tableName = "changelog")
public class ChangelogDao {
@DatabaseField(id = true)
private String id;
@DatabaseField
private Date createdAt;
@DatabaseField
private String comment;
public ChangelogDao() {
}
public ChangelogDao(String id, Date createdAt, String comment) {
this.id = id;
this.createdAt = createdAt;
this.comment = comment;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}