Compare commits
	
		
			2 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | eb1326c56a | ||
|  | 10cdb4360e | 
| @@ -7,7 +7,7 @@ Default values: | ||||
| ```.yaml | ||||
| matrix: | ||||
|   v1: true   # deprecated | ||||
|   v2: true | ||||
|   v2: 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: v2 disabled by default in order to preserve backward compatibility. | ||||
|  | ||||
| ## Terms | ||||
|  | ||||
| ###### Requires: No.  | ||||
|  | ||||
| Administrator can omit terms configuration. In this case the terms checking will be disabled. | ||||
|  | ||||
| Example: | ||||
| ```.yaml | ||||
| policy: | ||||
| @@ -45,7 +51,7 @@ Where: | ||||
| - `version` -- the terms version. | ||||
| - `lang` -- the term language. | ||||
| - `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. | ||||
|  | ||||
| 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`. | ||||
|  | ||||
| ###### Requires: No.  | ||||
|  | ||||
| In case the `none` algorithms ma1sd will be lookup using the v1 bulk API. | ||||
|  | ||||
| ```.yaml | ||||
| hashing: | ||||
|   enabled: true # enable or disable the hash lookup MSC2140 (default is false) | ||||
|   | ||||
| @@ -22,7 +22,7 @@ | ||||
| matrix: | ||||
|   domain: '' | ||||
|   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) | ||||
|  | ||||
| hashing: | ||||
|   enabled: false # enable or disable the hash lookup MSC2140 (default is false) | ||||
|   pepperLength: 20 # length of the pepper value (default is 20) | ||||
|   rotationPolicy: per_requests # or `per_seconds` how often the hashes will be updating | ||||
|   hashStorageType: sql # or `in_memory` where the hashes will be stored | ||||
|   algorithms: | ||||
|     - none   # the same as v1 bulk lookup | ||||
|     - sha256 # hash the 3PID and pepper. | ||||
|   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) | ||||
| #hashing: | ||||
| #  enabled: false # enable or disable the hash lookup MSC2140 (default is false) | ||||
| #  pepperLength: 20 # length of the pepper value (default is 20) | ||||
| #  rotationPolicy: per_requests # or `per_seconds` how often the hashes will be updating | ||||
| #  hashStorageType: sql # or `in_memory` where the hashes will be stored | ||||
| #  algorithms: | ||||
| #    - none   # the same as v1 bulk lookup | ||||
| #    - sha256 # hash the 3PID and pepper. | ||||
| #  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) | ||||
|  | ||||
| ### hash lookup for synapseSql provider. | ||||
| # synapseSql: | ||||
| @@ -132,19 +132,19 @@ hashing: | ||||
| #     query: 'select user_id as mxid, medium, address from user_threepids' # query for retrive 3PIDs for hashes. | ||||
|  | ||||
| #### MSC2140 (Terms) | ||||
| policy: | ||||
|   policies: | ||||
|     term_name: # term name | ||||
|       version: 1.0 # version | ||||
|       terms: | ||||
|         en:  # lang | ||||
|           name: term name en  # localized name | ||||
|           url: https://ma1sd.host.tld/term_en.html  # localized url | ||||
|         fe:  # lang | ||||
|           name: term name fr  # localized name | ||||
|           url: https://ma1sd.host.tld/term_fr.html  # localized url | ||||
|       regexp: | ||||
|         - '/_matrix/identity/v2/account.*' | ||||
|         - '/_matrix/identity/v2/hash_details' | ||||
|         - '/_matrix/identity/v2/lookup' | ||||
|  | ||||
| #policy: | ||||
| #  policies: | ||||
| #    term_name: # term name | ||||
| #      version: 1.0 # version | ||||
| #      terms: | ||||
| #        en:  # lang | ||||
| #          name: term name en  # localized name | ||||
| #          url: https://ma1sd.host.tld/term_en.html  # localized url | ||||
| #        fe:  # lang | ||||
| #          name: term name fr  # localized name | ||||
| #          url: https://ma1sd.host.tld/term_fr.html  # localized url | ||||
| #      regexp: | ||||
| #        - '/_matrix/identity/v2/account.*' | ||||
| #        - '/_matrix/identity/v2/hash_details' | ||||
| #        - '/_matrix/identity/v2/lookup' | ||||
| # | ||||
|   | ||||
| @@ -189,24 +189,33 @@ public class HttpMxisd { | ||||
|     } | ||||
|  | ||||
|     private void accountEndpoints(RoutingHandler routingHandler) { | ||||
|         MatrixConfig matrixConfig = m.getConfig().getMatrix(); | ||||
|         if (matrixConfig.isV2()) { | ||||
|             routingHandler.post(AccountRegisterHandler.Path, SaneHandler.around(new AccountRegisterHandler(m.getAccMgr()))); | ||||
|             wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.GET, sane(new AccountGetUserInfoHandler(m.getAccMgr())), | ||||
|                 AccountGetUserInfoHandler.Path, true); | ||||
|             wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.GET, sane(new AccountLogoutHandler(m.getAccMgr())), | ||||
|                 AccountLogoutHandler.Path, true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void termsEndpoints(RoutingHandler routingHandler) { | ||||
|         MatrixConfig matrixConfig = m.getConfig().getMatrix(); | ||||
|         if (matrixConfig.isV2()) { | ||||
|             routingHandler.get(GetTermsHandler.PATH, new GetTermsHandler(m.getConfig().getPolicy())); | ||||
|             routingHandler.post(AcceptTermsHandler.PATH, sane(new AcceptTermsHandler(m.getAccMgr()))); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void hashEndpoints(RoutingHandler routingHandler) { | ||||
|         MatrixConfig matrixConfig = m.getConfig().getMatrix(); | ||||
|         if (matrixConfig.isV2()) { | ||||
|             wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.GET, sane(new HashDetailsHandler(m.getHashManager())), | ||||
|                 HashDetailsHandler.PATH, true); | ||||
|             wrapWithTokenAndAuthorizationHandlers(routingHandler, Methods.POST, | ||||
|                 sane(new HashLookupHandler(m.getIdentity(), m.getHashManager())), HashLookupHandler.Path, true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void addEndpoints(RoutingHandler routingHandler, HttpString method, boolean useAuthorization, ApiHandler... handlers) { | ||||
|         for (ApiHandler handler : handlers) { | ||||
|   | ||||
| @@ -10,6 +10,7 @@ import io.kamax.mxisd.exception.BadRequestException; | ||||
| import io.kamax.mxisd.exception.InvalidCredentialsException; | ||||
| import io.kamax.mxisd.exception.NotFoundException; | ||||
| import io.kamax.mxisd.matrix.HomeserverFederationResolver; | ||||
| import io.kamax.mxisd.matrix.HomeserverVerifier; | ||||
| import io.kamax.mxisd.storage.IStorage; | ||||
| import io.kamax.mxisd.storage.ormlite.dao.AccountDao; | ||||
| import org.apache.http.HttpStatus; | ||||
| @@ -22,18 +23,10 @@ import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| 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.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
| import java.util.UUID; | ||||
| import javax.net.ssl.HostnameVerifier; | ||||
| import javax.net.ssl.SSLPeerUnverifiedException; | ||||
| import javax.net.ssl.SSLSession; | ||||
|  | ||||
| public class AccountManager { | ||||
|  | ||||
| @@ -80,7 +73,7 @@ public class AccountManager { | ||||
|             homeserverURL + "/_matrix/federation/v1/openid/userinfo?access_token=" + openIdToken.getAccessToken()); | ||||
|         String userId; | ||||
|         try (CloseableHttpClient httpClient = HttpClients.custom() | ||||
|             .setSSLHostnameVerifier(new MatrixHostnameVerifier(homeserverTarget.getDomain())).build()) { | ||||
|             .setSSLHostnameVerifier(new HomeserverVerifier(homeserverTarget.getDomain())).build()) { | ||||
|             try (CloseableHttpResponse response = httpClient.execute(getUserInfo)) { | ||||
|                 int statusCode = response.getStatusLine().getStatusCode(); | ||||
|                 if (statusCode == HttpStatus.SC_OK) { | ||||
| @@ -170,74 +163,4 @@ public class AccountManager { | ||||
|     public MatrixConfig getMatrixConfig() { | ||||
|         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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -64,7 +64,7 @@ public class MatrixConfig { | ||||
|     private String domain; | ||||
|     private Identity identity = new Identity(); | ||||
|     private boolean v1 = true; | ||||
|     private boolean v2 = true; | ||||
|     private boolean v2 = false; | ||||
|  | ||||
|     public String getDomain() { | ||||
|         return domain; | ||||
|   | ||||
| @@ -48,7 +48,7 @@ public class AccountRegisterHandler extends BasicHttpHandler { | ||||
|  | ||||
|         if (LOGGER.isInfoEnabled()) { | ||||
|             LOGGER.info("Registration from domain: {}, expired at {}", openIdToken.getMatrixServerName(), | ||||
|                 new Date(openIdToken.getExpiresIn())); | ||||
|                 new Date(System.currentTimeMillis() + openIdToken.getExpiresIn())); | ||||
|         } | ||||
|  | ||||
|         String token = accountManager.register(openIdToken); | ||||
|   | ||||
| @@ -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.lookup.BulkLookupRequest; | ||||
| 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.strategy.LookupStrategy; | ||||
| import io.undertow.server.HttpServerExchange; | ||||
| @@ -40,6 +42,7 @@ import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
|  | ||||
| public class HashLookupHandler extends LookupHandler implements ApiHandler { | ||||
|  | ||||
| @@ -89,6 +92,18 @@ public class HashLookupHandler extends LookupHandler implements ApiHandler { | ||||
|             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(); | ||||
|         List<ThreePidMapping> mappings = new ArrayList<>(); | ||||
|         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()); | ||||
|  | ||||
|         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) { | ||||
|   | ||||
| @@ -77,7 +77,8 @@ public class HomeserverVerifier implements HostnameVerifier { | ||||
|  | ||||
|     private boolean match(String altSubjectName) { | ||||
|         if (altSubjectName.startsWith("*.")) { | ||||
|             return altSubjectName.toLowerCase().endsWith(matrixHostname.toLowerCase()); | ||||
|             String subjectNameWithoutMask = altSubjectName.substring(1); // remove wildcard | ||||
|             return matrixHostname.toLowerCase().endsWith(subjectNameWithoutMask.toLowerCase()); | ||||
|         } else { | ||||
|             return matrixHostname.equalsIgnoreCase(altSubjectName); | ||||
|         } | ||||
|   | ||||
| @@ -39,6 +39,7 @@ import io.kamax.mxisd.storage.IStorage; | ||||
| import io.kamax.mxisd.storage.dao.IThreePidSessionDao; | ||||
| import io.kamax.mxisd.storage.ormlite.dao.ASTransactionDao; | ||||
| 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.HistoricalThreePidInviteIO; | ||||
| 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 org.apache.commons.lang.StringUtils; | ||||
| import org.apache.commons.lang3.tuple.Pair; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.sql.SQLException; | ||||
| import java.time.Instant; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| import java.util.UUID; | ||||
| @@ -59,6 +63,8 @@ import java.util.stream.Collectors; | ||||
|  | ||||
| public class OrmLiteSqlStorage implements IStorage { | ||||
|  | ||||
|     private static final Logger LOGGER = LoggerFactory.getLogger(OrmLiteSqlStorage.class); | ||||
|  | ||||
|     @FunctionalInterface | ||||
|     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<HistoricalThreePidInviteIO, String> expInvDao; | ||||
|     private Dao<ThreePidSessionDao, String> sessionDao; | ||||
|     private Dao<ASTransactionDao, String> asTxnDao; | ||||
|     private Dao<AccountDao, String> accountDao; | ||||
|     private Dao<AcceptedDao, String> acceptedDao; | ||||
|     private Dao<AcceptedDao, Long> acceptedDao; | ||||
|     private Dao<HashDao, String> hashDao; | ||||
|     private Dao<ChangelogDao, String> changelogDao; | ||||
|  | ||||
|     public OrmLiteSqlStorage(MxisdConfig cfg) { | ||||
|         this(cfg.getStorage().getBackend(), cfg.getStorage().getProvider().getSqlite().getDatabase()); | ||||
| @@ -96,6 +107,7 @@ public class OrmLiteSqlStorage implements IStorage { | ||||
|  | ||||
|         withCatcher(() -> { | ||||
|             ConnectionSource connPool = new JdbcConnectionSource("jdbc:" + backend + ":" + path); | ||||
|             changelogDao = createDaoAndTable(connPool, ChangelogDao.class); | ||||
|             invDao = createDaoAndTable(connPool, ThreePidInviteIO.class); | ||||
|             expInvDao = createDaoAndTable(connPool, HistoricalThreePidInviteIO.class); | ||||
|             sessionDao = createDaoAndTable(connPool, ThreePidSessionDao.class); | ||||
| @@ -103,10 +115,26 @@ public class OrmLiteSqlStorage implements IStorage { | ||||
|             accountDao = createDaoAndTable(connPool, AccountDao.class); | ||||
|             acceptedDao = createDaoAndTable(connPool, AcceptedDao.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 { | ||||
|         LOGGER.info("Create the dao: {}", c.getSimpleName()); | ||||
|         Dao<V, K> dao = DaoManager.createDao(connPool, c); | ||||
|         TableUtils.createTableIfNotExists(connPool, c); | ||||
|         return dao; | ||||
|   | ||||
| @@ -26,7 +26,10 @@ import com.j256.ormlite.table.DatabaseTable; | ||||
| @DatabaseTable(tableName = "accepted") | ||||
| public class AcceptedDao { | ||||
|  | ||||
|     @DatabaseField(canBeNull = false, id = true) | ||||
|     @DatabaseField(generatedId = true) | ||||
|     private Long id; | ||||
|  | ||||
|     @DatabaseField(canBeNull = false) | ||||
|     private String url; | ||||
|  | ||||
|     @DatabaseField(canBeNull = false) | ||||
| @@ -45,6 +48,14 @@ public class AcceptedDao { | ||||
|         this.acceptedAt = acceptedAt; | ||||
|     } | ||||
|  | ||||
|     public Long getId() { | ||||
|         return id; | ||||
|     } | ||||
|  | ||||
|     public void setId(Long id) { | ||||
|         this.id = id; | ||||
|     } | ||||
|  | ||||
|     public String getUrl() { | ||||
|         return url; | ||||
|     } | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user