diff --git a/back-end-projects/Explorer/account.json b/back-end-projects/Explorer/account.json new file mode 100644 index 00000000..79b1fa13 --- /dev/null +++ b/back-end-projects/Explorer/account.json @@ -0,0 +1 @@ +{"accounts":[],"createTime":"2020-03-26T10:46:52Z","defaultAccountAddress":"","defaultOntid":"did:ont:ARR7Rk4hpvnkAAWkyHGtrF2H3htHWrKFby","identities":[{"controls":[{"address":"ARR7Rk4hpvnkAAWkyHGtrF2H3htHWrKFby","algorithm":"ECDSA","enc-alg":"aes-256-gcm","hash":"sha256","id":"keys-1","key":"KDCGqt8JbwcN6wKQasQcUrDjjIUy152SfE1dIVvQjYGmuhzd74dnLnLhjgfJAkJY","parameters":{"curve":"P-256"},"publicKey":"034044d1ab03d42543e806c4242fe0ab42f0df530c7548f2078e00a79b087892bb","salt":"hf/9mY5kH9567GZQYnn4hw=="}],"isDefault":true,"label":"c7b82a36","lock":false,"ontid":"did:ont:ARR7Rk4hpvnkAAWkyHGtrF2H3htHWrKFby"},{"controls":[{"address":"Ae6XnePYWiBUALD2c2EdnuDAAWEsqf2JGr","algorithm":"ECDSA","enc-alg":"aes-256-gcm","hash":"sha256","id":"keys-1","key":"zgNPyJb3UtIA2jdHoS2I6RgnYPRc50cC89gIN9frbnZMtp+pMSm9iR3Oxd9/kIBQ","parameters":{"curve":"P-256"},"publicKey":"0376104dd7bba89580540f9e923a32ad9470af8759774c578936d96004fc492218","salt":"oNyhAmy2RLtv64wmnAlK6g=="}],"isDefault":false,"label":"06c59f9d","lock":false,"ontid":"did:ont:Ae6XnePYWiBUALD2c2EdnuDAAWEsqf2JGr"}],"name":"com.github.ontio","scrypt":{"dkLen":64,"n":16384,"p":8,"r":8},"version":"1.0"} diff --git a/back-end-projects/Explorer/config/application.properties b/back-end-projects/Explorer/config/application.properties index ba2b40f4..a3ef6b4b 100644 --- a/back-end-projects/Explorer/config/application.properties +++ b/back-end-projects/Explorer/config/application.properties @@ -65,6 +65,20 @@ reqlimit.expire.millisecond=1000 swagger.enable=true + +##user login +login.callbackUrl= +login.qrcode.url= + +identity.ontid = +identity.password = +identity.salt = + +jwt.accessTokenExpireTime=120 +jwt.encryptJWTKey= + +oneUser.address.count.limit=5 + coinmarketcap.api.key= coinmarketcap.api.host=https://pro-api.coinmarketcap.com/ coinmarketcap.refresh.interval=15 \ No newline at end of file diff --git a/back-end-projects/Explorer/pom.xml b/back-end-projects/Explorer/pom.xml index a921634d..108212c7 100644 --- a/back-end-projects/Explorer/pom.xml +++ b/back-end-projects/Explorer/pom.xml @@ -24,6 +24,7 @@ 1.8 2.9.2 2.3.0 + 3.4.1 @@ -185,6 +186,12 @@ ${retrofit2.version} + + com.auth0 + java-jwt + ${jwt.version} + + diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/SimpleCORSFilter.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/SimpleCORSFilter.java index 7078e561..3a06d42f 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/SimpleCORSFilter.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/SimpleCORSFilter.java @@ -19,6 +19,7 @@ package com.github.ontio; +import com.github.ontio.util.ConstantParam; import org.springframework.stereotype.Component; import javax.servlet.*; @@ -29,26 +30,26 @@ @Component public class SimpleCORSFilter implements Filter { - public void doFilter(ServletRequest req, ServletResponse res, + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - HttpServletResponse response = (HttpServletResponse) res; - HttpServletRequest request = (HttpServletRequest) req; - String origin = request.getHeader("Origin"); - response.setHeader("Access-Control-Allow-Origin", "*"); - response.setHeader("Access-Control-Allow-Credentials", "true"); - response.setHeader("Access-Control-Allow-Methods", - "POST, PUT, GET, OPTIONS, DELETE"); - response.setHeader("Access-Control-Max-Age", "3600"); - response.setHeader( - "Access-Control-Allow-Headers", - "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With"); - chain.doFilter(req, res); - } - - public void init(FilterConfig filterConfig) { - } - - public void destroy() { - } + HttpServletResponse response = (HttpServletResponse) res; + HttpServletRequest request = (HttpServletRequest) req; + String origin = request.getHeader("Origin"); + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Credentials", "true"); + response.setHeader("Access-Control-Allow-Methods", + "POST, PUT, GET, OPTIONS, DELETE"); + response.setHeader("Access-Control-Max-Age", "3600"); + response.setHeader( + "Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers")); + response.setHeader("Access-Control-Expose-Headers", ConstantParam.HTTPHEADER_TOKEN); + chain.doFilter(req, res); + } + + public void init(FilterConfig filterConfig) { + } + + public void destroy() { + } } \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/config/ParamsConfig.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/config/ParamsConfig.java index 849c7ca7..827d0931 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/config/ParamsConfig.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/config/ParamsConfig.java @@ -141,4 +141,23 @@ public String getContractHash(String token) { } } + @Value("${login.callbackUrl:https://explorer.ont.io/v2/users/login}") + public String loginCallbackUrl; + + @Value("${identity.ontid}") + public String IDENTITY_ONTID; + + @Value("${identity.password}") + public String IDENTITY_PASSWORD; + + @Value("${identity.salt}") + public String IDENTITY_SALT; + + @Value("${login.qrcode.url:https://explorer.ont.io/v2/users/login_qrcode/}") + public String loginQrCodeUrl; + + + @Value("${oneUser.address.count.limit}") + public Integer oneUserAddressCountLimit; + } \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/TokenController.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/TokenController.java index 4dd6aa75..22d069cf 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/TokenController.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/TokenController.java @@ -10,11 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.validation.constraints.Max; import javax.validation.constraints.Min; @@ -72,9 +68,9 @@ public ResponseBean queryTokenDetail(@PathVariable("token_type") @Pattern(regexp @GetMapping(value = "/oep8/{contract_hash}/{token_name}/transactions") public ResponseBean queryOep8TxsByPage(@PathVariable("contract_hash") @Length(min = 40, max = 40, message = "Incorrect " + "contract hash") String contractHash, - @PathVariable("token_name") String tokenName, - @RequestParam("page_size") @Min(1) @Max(20) Integer pageSize, - @RequestParam("page_number") @Min(1) Integer pageNumber) { + @PathVariable("token_name") String tokenName, + @RequestParam("page_size") @Min(1) @Max(20) Integer pageSize, + @RequestParam("page_number") @Min(1) Integer pageNumber) { log.info("###{}.{} begin...contract_hash:{},token_name:{}", CLASS_NAME, Helper.currentMethod(), contractHash, tokenName); @@ -120,4 +116,14 @@ public ResponseBean queryPrice( return tokenService.queryPrice(token, fiat); } + + @ApiOperation(value = "Get oep logos") + @GetMapping(value = "/logos") + public ResponseBean queryOepLogos(@RequestParam("contract_hash") @Length(min = 40, max = 40, message = "Incorrect contract hash") String contractHash, + @RequestParam("page_size") @Min(1) @Max(50) int pageSize, + @RequestParam("page_number") @Min(1) int pageNumber) { + log.info("###{}.{} begin...", CLASS_NAME, Helper.currentMethod()); + return tokenService.queryOepLogos(contractHash, pageSize, pageNumber); + } + } diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/UserController.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/UserController.java new file mode 100644 index 00000000..a8dd64eb --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/UserController.java @@ -0,0 +1,159 @@ +package com.github.ontio.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.ontio.exception.ExplorerException; +import com.github.ontio.model.common.ResponseBean; +import com.github.ontio.model.dao.User; +import com.github.ontio.model.dao.UserAddress; +import com.github.ontio.model.dto.login.CallBackDto; +import com.github.ontio.model.dto.login.CallBackResponse; +import com.github.ontio.model.dto.login.QrCodeDto; +import com.github.ontio.service.IUserService; +import com.github.ontio.util.ConstantParam; +import com.github.ontio.util.ErrorInfo; +import com.github.ontio.util.Helper; +import com.github.ontio.util.JwtUtil; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import javax.validation.constraints.Pattern; +import java.util.List; + +/** + * @author zhouq + * @version 1.0 + * @date 2020/3/24 + */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/v2/users/") +@Validated +public class UserController { + + private final String CLASS_NAME = this.getClass().getSimpleName(); + + private final IUserService userService; + + + @ApiOperation(value = "Web Query login qrcode") + @GetMapping(value = "/web_login_qrcode") + public ResponseBean queryWebQrCode() { + ResponseBean rs = userService.queryWebQrCode(); + return rs; + } + + @ApiOperation(value = "ONTO APP Query login qrcode") + @GetMapping(value = "/login_qrcode/{qrcode_id}") + public QrCodeDto queryQrCode(@PathVariable("qrcode_id") String qrcodeId) { + QrCodeDto rs = userService.queryQrCode(qrcodeId); + return rs; + } + + + @ApiOperation(value = "Query login user info") + @GetMapping(value = "/login_user_info") + public ResponseBean queryLoginUserInfo(@RequestParam("code") String code) { + ResponseBean rs = userService.queryLoginUserInfo(code); + return rs; + } + + + @ApiOperation(value = "ONTO User login") + @PostMapping(value = "/login") + public CallBackResponse userLogin(@RequestBody JSONObject jsonObject) { + log.info("###{}.{} begin...param:{}", CLASS_NAME, Helper.currentMethod(), jsonObject); + CallBackDto callBackDto = new CallBackDto(); + callBackDto.setSigner(jsonObject.getString("signer")); + callBackDto.setSignedTx(jsonObject.getString("signedTx")); + CallBackDto.CallbackExtraData callbackExtraData = CallBackDto.CallbackExtraData.builder() + .id(jsonObject.getJSONObject("extraData").getString("id")) + .build(); + callBackDto.setExtraData(callbackExtraData); + CallBackResponse rs = userService.login(callBackDto); + return rs; + } + + + @ApiImplicitParams({@ApiImplicitParam(paramType = "header", dataType = "String", name = "ONT_EXP_TOKEN", value = "login token", required = true)}) + @ApiOperation(value = "Query user addresses") + @GetMapping(value = "/addresses") + public ResponseBean queryUserAddresses(@RequestParam("ont_id") @Pattern(regexp = "did:ont:[A-Za-z0-9]{34}", message = "Incorrect ONT ID format") String ontId) { + log.info("###{}.{} begin...ontId:{}", CLASS_NAME, Helper.currentMethod(), ontId); + checkToken(ontId); + ResponseBean rs = userService.queryUserAddresses(ontId); + refreshToken(ontId); + return rs; + } + + + @ApiImplicitParams({@ApiImplicitParam(paramType = "header", dataType = "String", name = "ONT_EXP_TOKEN", value = "login token", required = true)}) + @ApiOperation(value = "Add or Update user addresses") + @PostMapping(value = "/addresses") + public ResponseBean addOrUpdateUserAddresses(@RequestParam("ont_id") @Pattern(regexp = "did:ont:[A-Za-z0-9]{34}", message = "Incorrect ONT ID format") String ontId, + @RequestBody @Valid List userAddresses) { + log.info("###{}.{} begin...ontId:{}", CLASS_NAME, Helper.currentMethod(), ontId); + checkToken(ontId); + ResponseBean rs = userService.addOrUpdateUserAddresses(userAddresses, ontId); + refreshToken(ontId); + return rs; + } + + + @ApiImplicitParams({@ApiImplicitParam(paramType = "header", dataType = "String", name = "ONT_EXP_TOKEN", value = "login token", required = true)}) + @ApiOperation(value = "Delete user address") + @DeleteMapping(value = "/addresses") + public ResponseBean delUserAddress(@RequestParam("ont_id") @Pattern(regexp = "did:ont:[A-Za-z0-9]{34}", message = "Incorrect ONT ID format") String ontId, + @RequestBody JSONObject jsonObject) { + log.info("###{}.{} begin...ontId:{}", CLASS_NAME, Helper.currentMethod(), ontId); + checkToken(ontId); + ResponseBean rs = userService.delUserAddress(jsonObject.getString("address"), ontId); + refreshToken(ontId); + return rs; + } + + + @ApiImplicitParams({@ApiImplicitParam(paramType = "header", dataType = "String", name = "ONT_EXP_TOKEN", value = "login token", required = true)}) + @ApiOperation(value = "Update user information") + @PostMapping + public ResponseBean updateUser(@RequestParam("ont_id") @Pattern(regexp = "did:ont:[A-Za-z0-9]{34}", message = "Incorrect ONT ID format") String ontId, + @RequestBody @Validated User user) { + log.info("###{}.{} begin...ontId:{}", CLASS_NAME, Helper.currentMethod(), ontId); + checkToken(ontId); + user.setOntId(ontId); + ResponseBean rs = userService.updateUser(user); + refreshToken(ontId); + return rs; + } + + + private void checkToken(String ontId) { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + String token = request.getHeader(ConstantParam.HTTPHEADER_TOKEN); + if (Helper.isEmptyOrNull(token)) { + throw new ExplorerException(ErrorInfo.TOKEN_EMPTY); + } + if (!JwtUtil.verifyToken(token)) { + throw new ExplorerException(ErrorInfo.TOKEN_EXPIRED); + } else if (!JwtUtil.getClaim(token, ConstantParam.JWT_LOGINID).asString().equals(ontId)) { + throw new ExplorerException(ErrorInfo.TOKEN_UNMATCH); + } + } + + private void refreshToken(String ontId) { + String newToken = JwtUtil.signToken(ontId); + HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); + resp.setHeader(ConstantParam.HTTPHEADER_TOKEN, newToken); + } + +} diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/exception/ExplorerException.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/exception/ExplorerException.java index 0e91dbf8..546fcda6 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/exception/ExplorerException.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/exception/ExplorerException.java @@ -1,5 +1,6 @@ package com.github.ontio.exception; +import com.github.ontio.util.ErrorInfo; import lombok.Data; import lombok.EqualsAndHashCode; @@ -19,6 +20,18 @@ public ExplorerException(Integer code, String msg, Object result){ this.result = result; } + public ExplorerException(ErrorInfo errorInfo, Object result){ + this.code = errorInfo.code(); + this.msg = errorInfo.desc(); + this.result = result; + } + + public ExplorerException(ErrorInfo errorInfo){ + this.code = errorInfo.code(); + this.msg = errorInfo.desc(); + this.result = false; + } + public ExplorerException(){super();} public ExplorerException(String msg){super(msg);} diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/AddressBlacklistMapper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/AddressBlacklistMapper.java new file mode 100644 index 00000000..e3f07b94 --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/AddressBlacklistMapper.java @@ -0,0 +1,7 @@ +package com.github.ontio.mapper; + +import com.github.ontio.model.dao.AddressBlacklist; +import tk.mybatis.mapper.common.Mapper; + +public interface AddressBlacklistMapper extends Mapper { +} \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/OepLogoMapper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/OepLogoMapper.java new file mode 100644 index 00000000..9a99e4c0 --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/OepLogoMapper.java @@ -0,0 +1,7 @@ +package com.github.ontio.mapper; + +import com.github.ontio.model.dao.OepLogo; +import tk.mybatis.mapper.common.Mapper; + +public interface OepLogoMapper extends Mapper { +} \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserAddressMapper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserAddressMapper.java new file mode 100644 index 00000000..41e1629a --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserAddressMapper.java @@ -0,0 +1,12 @@ +package com.github.ontio.mapper; + +import com.github.ontio.model.dao.UserAddress; +import tk.mybatis.mapper.common.Mapper; + +import java.util.List; + +public interface UserAddressMapper extends Mapper { + + int saveUserAddress(List userAddresses); + +} \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserMapper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserMapper.java new file mode 100644 index 00000000..f7d444dc --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserMapper.java @@ -0,0 +1,10 @@ +package com.github.ontio.mapper; + +import com.github.ontio.model.dao.User; +import tk.mybatis.mapper.common.Mapper; + +public interface UserMapper extends Mapper { + + int saveUser(User user); + +} \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/common/RedisKey.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/common/RedisKey.java new file mode 100644 index 00000000..87a0d5e0 --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/common/RedisKey.java @@ -0,0 +1,12 @@ +package com.github.ontio.model.common; + +/** + * @author zhouq + * @version 1.0 + * @date 2020/3/25 + */ +public class RedisKey { + + public static final String USERLOGIN_QRCODEID = "userLogin:qrCodeId:%s"; + +} diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/AddressBlacklist.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/AddressBlacklist.java new file mode 100644 index 00000000..73004555 --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/AddressBlacklist.java @@ -0,0 +1,68 @@ +package com.github.ontio.model.dao; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +@Table(name = "tbl_address_blacklist") +public class AddressBlacklist { + @Id + @GeneratedValue(generator = "JDBC") + private String address; + + /** + * 备注 + */ + private String note; + + @Column(name = "create_time") + private Date createTime; + + /** + * @return address + */ + public String getAddress() { + return address; + } + + /** + * @param address + */ + public void setAddress(String address) { + this.address = address == null ? null : address.trim(); + } + + /** + * 获取备注 + * + * @return note - 备注 + */ + public String getNote() { + return note; + } + + /** + * 设置备注 + * + * @param note 备注 + */ + public void setNote(String note) { + this.note = note == null ? null : note.trim(); + } + + /** + * @return create_time + */ + public Date getCreateTime() { + return createTime; + } + + /** + * @param createTime + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/OepLogo.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/OepLogo.java new file mode 100644 index 00000000..6a497fd0 --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/OepLogo.java @@ -0,0 +1,166 @@ +package com.github.ontio.model.dao; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.github.ontio.util.TxDateSerializer; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +@Table(name = "tbl_oep_logo") +public class OepLogo { + @Id + @GeneratedValue(generator = "JDBC") + private Integer id; + + /** + * 合约hash + */ + @Column(name = "contract_hash") + private String contractHash; + + /** + * oep5,oep8 + */ + private String type; + + /** + * 合约token id + */ + @Column(name = "token_id") + private String tokenId; + + /** + * logo链接 + */ + private String logo; + + /** + * token名称 + */ + private String name; + + @JsonSerialize(using = TxDateSerializer.class) + @Column(name = "create_time") + private Date createTime; + + /** + * @return id + */ + public Integer getId() { + return id; + } + + /** + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * 获取合约hash + * + * @return contract_hash - 合约hash + */ + public String getContractHash() { + return contractHash; + } + + /** + * 设置合约hash + * + * @param contractHash 合约hash + */ + public void setContractHash(String contractHash) { + this.contractHash = contractHash == null ? null : contractHash.trim(); + } + + /** + * 获取oep5,oep8 + * + * @return type - oep5,oep8 + */ + public String getType() { + return type; + } + + /** + * 设置oep5,oep8 + * + * @param type oep5,oep8 + */ + public void setType(String type) { + this.type = type == null ? null : type.trim(); + } + + /** + * 获取合约token id + * + * @return token_id - 合约token id + */ + public String getTokenId() { + return tokenId; + } + + /** + * 设置合约token id + * + * @param tokenId 合约token id + */ + public void setTokenId(String tokenId) { + this.tokenId = tokenId == null ? null : tokenId.trim(); + } + + /** + * 获取logo链接 + * + * @return logo - logo链接 + */ + public String getLogo() { + return logo; + } + + /** + * 设置logo链接 + * + * @param logo logo链接 + */ + public void setLogo(String logo) { + this.logo = logo == null ? null : logo.trim(); + } + + /** + * 获取token名称 + * + * @return name - token名称 + */ + public String getName() { + return name; + } + + /** + * 设置token名称 + * + * @param name token名称 + */ + public void setName(String name) { + this.name = name == null ? null : name.trim(); + } + + /** + * @return create_time + */ + public Date getCreateTime() { + return createTime; + } + + /** + * @param createTime + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/User.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/User.java new file mode 100644 index 00000000..922ac0cb --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/User.java @@ -0,0 +1,146 @@ +package com.github.ontio.model.dao; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.github.ontio.util.TxDateSerializer; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; +import java.util.Date; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tbl_user") +public class User { + /** + * ONT ID + */ + @Id + @Column(name = "ont_id") + @GeneratedValue(generator = "JDBC") + private String ontId; + + /** + * 用户名 + */ + @Column(name = "user_name") + private String userName; + + /** + * 邮箱 + */ + @NotEmpty + @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "email format error") + private String email; + + /** + * 创建时间 + */ + @JsonSerialize(using = TxDateSerializer.class) + @Column(name = "create_time") + private Date createTime; + + /** + * 上次登录时间 + */ + @JsonSerialize(using = TxDateSerializer.class) + @Column(name = "last_login_time") + private Date lastLoginTime; + + /** + * 获取ONT ID + * + * @return ont_id - ONT ID + */ + public String getOntId() { + return ontId; + } + + /** + * 设置ONT ID + * + * @param ontId ONT ID + */ + public void setOntId(String ontId) { + this.ontId = ontId == null ? null : ontId.trim(); + } + + /** + * 获取用户名 + * + * @return user_name - 用户名 + */ + public String getUserName() { + return userName; + } + + /** + * 设置用户名 + * + * @param userName 用户名 + */ + public void setUserName(String userName) { + this.userName = userName == null ? null : userName.trim(); + } + + /** + * 获取邮箱 + * + * @return email - 邮箱 + */ + public String getEmail() { + return email; + } + + /** + * 设置邮箱 + * + * @param email 邮箱 + */ + public void setEmail(String email) { + this.email = email == null ? null : email.trim(); + } + + /** + * 获取创建时间 + * + * @return create_time - 创建时间 + */ + public Date getCreateTime() { + return createTime; + } + + /** + * 设置创建时间 + * + * @param createTime 创建时间 + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + /** + * 获取上次登录时间 + * + * @return last_login_time - 上次登录时间 + */ + public Date getLastLoginTime() { + return lastLoginTime; + } + + /** + * 设置上次登录时间 + * + * @param lastLoginTime 上次登录时间 + */ + public void setLastLoginTime(Date lastLoginTime) { + this.lastLoginTime = lastLoginTime; + } +} \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/UserAddress.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/UserAddress.java new file mode 100644 index 00000000..06eb0a2f --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/UserAddress.java @@ -0,0 +1,159 @@ +package com.github.ontio.model.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "tbl_user_address") +public class UserAddress { + @Id + @GeneratedValue(generator = "JDBC") + private Integer id; + + /** + * ONT ID + */ + @Column(name = "ont_id") + private String ontId; + + /** + * 地址 + */ + @NotEmpty + @Pattern(regexp = "A[A-Za-z0-9]{33}") + private String address; + + /** + * 地址备注 + */ + private String note; + + /** + * 监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金 + */ + @Min(0) + @Max(3) + private Integer strategy; + + /** + * 1:监听oep资产 0:不监听oep资产 + */ + @Column(name = "include_oep_token") + private Boolean includeOepToken; + + /** + * @return id + */ + public Integer getId() { + return id; + } + + /** + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * 获取ONT ID + * + * @return ont_id - ONT ID + */ + public String getOntId() { + return ontId; + } + + /** + * 设置ONT ID + * + * @param ontId ONT ID + */ + public void setOntId(String ontId) { + this.ontId = ontId == null ? null : ontId.trim(); + } + + /** + * 获取地址 + * + * @return address - 地址 + */ + public String getAddress() { + return address; + } + + /** + * 设置地址 + * + * @param address 地址 + */ + public void setAddress(String address) { + this.address = address == null ? null : address.trim(); + } + + /** + * 获取地址备注 + * + * @return note - 地址备注 + */ + public String getNote() { + return note; + } + + /** + * 设置地址备注 + * + * @param note 地址备注 + */ + public void setNote(String note) { + this.note = note == null ? null : note.trim(); + } + + /** + * 获取监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金 + * + * @return strategy - 监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金 + */ + public Integer getStrategy() { + return strategy; + } + + /** + * 设置监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金 + * + * @param strategy 监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金 + */ + public void setStrategy(Integer strategy) { + this.strategy = strategy; + } + + /** + * 获取1:监听oep资产 0:不监听oep资产 + * + * @return include_oep_token - 1:监听oep资产 0:不监听oep资产 + */ + public Boolean getIncludeOepToken() { + return includeOepToken; + } + + /** + * 设置1:监听oep资产 0:不监听oep资产 + * + * @param includeOepToken 1:监听oep资产 0:不监听oep资产 + */ + public void setIncludeOepToken(Boolean includeOepToken) { + this.includeOepToken = includeOepToken; + } +} \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackDto.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackDto.java new file mode 100644 index 00000000..f080e5aa --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackDto.java @@ -0,0 +1,31 @@ +package com.github.ontio.model.dto.login; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author zhouq + * @version 1.0 + * @date 2020/3/25 + */ +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +public class CallBackDto { + + private String signer; + private String signedTx; + private CallbackExtraData extraData; + + @NoArgsConstructor + @AllArgsConstructor + @Builder + @Data + public static class CallbackExtraData{ + private String id; + } + +} diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackResponse.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackResponse.java new file mode 100644 index 00000000..68828f65 --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackResponse.java @@ -0,0 +1,50 @@ +package com.github.ontio.model.dto.login; + +import com.alibaba.fastjson.JSONObject; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +/** + * @author zhouq + * @version 1.0 + * @date 2020/3/25 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Data +public class CallBackResponse { + private String action; + private String version; + private long error; + private String id; + private JSONObject result; + + + public static CallBackResponse successResponse(JSONObject object) { + CallBackResponse callBackResponse = CallBackResponse.builder() + .action("") + .version("1.0.0") + .id(UUID.randomUUID().toString()) + .error(0L) + .result(object) + .build(); + return callBackResponse; + } + + public static CallBackResponse errorResponse(long error) { + CallBackResponse callBackResponse = CallBackResponse.builder() + .action("") + .version("1.0.0") + .id(UUID.randomUUID().toString()) + .error(error) + .result(new JSONObject()) + .build(); + return callBackResponse; + } + +} diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/QrCodeDto.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/QrCodeDto.java new file mode 100644 index 00000000..2c57579e --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/QrCodeDto.java @@ -0,0 +1,112 @@ +package com.github.ontio.model.dto.login; + +import com.github.ontio.util.JacksonUtil; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.List; + +/** + * @author zhouq + * @version 1.0 + * @date 2020/3/25 + */ +@Builder +@Data +@AllArgsConstructor +@NoArgsConstructor +public class QrCodeDto { + + private String callback; + private String chain; + private String data; + private long exp; + private String id; + private String requester; + private String signature; + private String signer; + private String ver; + + + public static QrCodeDto mainNetLoginQrCode(String id, String requester, String signature, QrCodeData qrCodeData, String callback, long exp) { + QrCodeDto qrCodeDto = QrCodeDto.builder() + .ver("1.0.0") + .id(id) + .requester(requester) + .signature(signature) + .signer("") + .data(JacksonUtil.beanToJSonStr(qrCodeData)) + .callback(callback) + .exp(exp) + .chain("Mainnet") + .build(); + return qrCodeDto; + } + + public static QrCodeDto testNetLoginQrCode(String id, String requester, String signature, QrCodeData qrCodeData, String callback, long exp) { + QrCodeDto qrCodeDto = QrCodeDto.builder() + .ver("1.0.0") + .id(id) + .requester(requester) + .signature(signature) + .signer("") + .data(JacksonUtil.beanToJSonStr(qrCodeData)) + .callback(callback) + .exp(exp) + .chain("Testnet") + .build(); + return qrCodeDto; + } + + + @NoArgsConstructor + @AllArgsConstructor + @Builder + @Data + public static class QrCodeData { + private String action; + private QrCodeDataParam params; + } + + @NoArgsConstructor + @AllArgsConstructor + @Builder + @Data + public static class QrCodeDataParam { + private QrCodeDataParamDetail invokeConfig; + } + + @NoArgsConstructor + @AllArgsConstructor + @Builder + @Data + public static class QrCodeDataParamDetail { + private String contractHash; + private List functions; + private BigDecimal gasLimit; + private BigDecimal gasPrice; + private String payer; + } + + @NoArgsConstructor + @AllArgsConstructor + @Builder + @Data + public static class QrCodeDataParamFun { + private List args; + private String operation; + } + + @NoArgsConstructor + @AllArgsConstructor + @Builder + @Data + public static class QrCodeDataParamFunArg { + private String name; + private String value; + } + +} diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/ITokenService.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/ITokenService.java index 40bbc5a3..79ba7ed8 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/ITokenService.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/ITokenService.java @@ -24,4 +24,6 @@ public interface ITokenService { ResponseBean queryPrice(String token, String fiat); + ResponseBean queryOepLogos(String contractHash, int pageSize, int pageNumber); + } diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/IUserService.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/IUserService.java new file mode 100644 index 00000000..c26dc991 --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/IUserService.java @@ -0,0 +1,35 @@ +package com.github.ontio.service; + +import com.github.ontio.model.common.ResponseBean; +import com.github.ontio.model.dao.User; +import com.github.ontio.model.dao.UserAddress; +import com.github.ontio.model.dto.login.CallBackDto; +import com.github.ontio.model.dto.login.CallBackResponse; +import com.github.ontio.model.dto.login.QrCodeDto; + +import java.util.List; + +/** + * @author zhouq + * @version 1.0 + * @date 2020/3/24 + */ +public interface IUserService { + + ResponseBean queryWebQrCode(); + + QrCodeDto queryQrCode(String qrcodeId); + + ResponseBean queryLoginUserInfo(String code); + + CallBackResponse login(CallBackDto callBackDto); + + ResponseBean queryUserAddresses(String ontId); + + ResponseBean addOrUpdateUserAddresses(List userAddresses, String ontId); + + ResponseBean delUserAddress(String address, String ontId); + + ResponseBean updateUser(User user); + +} diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/ContractServiceImpl.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/ContractServiceImpl.java index cfe9df50..17ea66e0 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/ContractServiceImpl.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/ContractServiceImpl.java @@ -57,6 +57,7 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -144,6 +145,7 @@ public ResponseBean queryTxsByContractHash(String contractType, String contractH //TODO 云斗龙特殊查询,多asset_name,json_url字段。后续oep5需要统一规范 if (paramsConfig.OEP5_DRAGON_CONTRACTHASH.equals(contractHash)) { List oep5TxDetailDtos = oep5TxDetailMapper.selectTxs4Dragon(contractHash, start, pageSize); + oep5TxDetailDtos = filterDragonTxDetails(oep5TxDetailDtos); count = oep5TxDetailMapper.selectCountByCalledContracthash(contractHash); pageResponseBean = new PageResponseBean(oep5TxDetailDtos, count); } else { @@ -191,6 +193,7 @@ public ResponseBean queryTxsByContractHash(String contractHash, Integer pageNumb //TODO 云斗龙特殊查询,多asset_name,json_url字段。后续oep5需要统一规范 if (paramsConfig.OEP5_DRAGON_CONTRACTHASH.equals(contractHash)) { List oep5TxDetailDtos = oep5TxDetailMapper.selectTxs4Dragon(contractHash, start, pageSize); + oep5TxDetailDtos = filterDragonTxDetails(oep5TxDetailDtos); count = oep5TxDetailMapper.selectCountByCalledContracthash(contractHash); pageResponseBean = new PageResponseBean(oep5TxDetailDtos, count); } else { @@ -636,4 +639,21 @@ private long getDaysAgo0HourTimestamp(int days) { return zeroHourTimestamp; } + private List filterDragonTxDetails(List details) { + if (details == null || details.isEmpty()) { + return details; + } + Map detailMap = new LinkedHashMap<>(); + details.forEach(detail -> detailMap.compute(detail.getTxHash(), (k, v) -> { + if (v == null) { + return detail; + } else if (detail.getAssetName() != null && detail.getAssetName().startsWith("HyperDragons")) { + return detail; + } else { + return v; + } + })); + return new ArrayList<>(detailMap.values()); + } + } diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/TokenServiceImpl.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/TokenServiceImpl.java index 8c44eda2..30654914 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/TokenServiceImpl.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/TokenServiceImpl.java @@ -3,19 +3,11 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.ontio.config.ParamsConfig; -import com.github.ontio.mapper.Oep4Mapper; -import com.github.ontio.mapper.Oep5Mapper; -import com.github.ontio.mapper.Oep8Mapper; -import com.github.ontio.mapper.Oep8TxDetailMapper; -import com.github.ontio.mapper.RankingMapper; -import com.github.ontio.mapper.TokenDailyAggregationMapper; +import com.github.ontio.mapper.*; import com.github.ontio.model.common.PageResponseBean; import com.github.ontio.model.common.ResponseBean; -import com.github.ontio.model.dto.Oep4DetailDto; -import com.github.ontio.model.dto.Oep5DetailDto; -import com.github.ontio.model.dto.Oep8DetailDto; -import com.github.ontio.model.dto.TokenPriceDto; -import com.github.ontio.model.dto.TxDetailDto; +import com.github.ontio.model.dao.OepLogo; +import com.github.ontio.model.dto.*; import com.github.ontio.model.dto.ranking.TokenRankingDto; import com.github.ontio.service.ITokenService; import com.github.ontio.util.ConstantParam; @@ -28,13 +20,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import tk.mybatis.mapper.entity.Example; import java.time.Duration; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -53,11 +42,12 @@ public class TokenServiceImpl implements ITokenService { private final TokenDailyAggregationMapper tokenDailyAggregationMapper; private final RankingMapper rankingMapper; private final CoinMarketCapApi coinMarketCapApi; + private final OepLogoMapper oepLogoMapper; @Autowired public TokenServiceImpl(Oep4Mapper oep4Mapper, Oep5Mapper oep5Mapper, Oep8Mapper oep8Mapper, - Oep8TxDetailMapper oep8TxDetailMapper, TokenDailyAggregationMapper tokenDailyAggregationMapper, - RankingMapper rankingMapper, CoinMarketCapApi coinMarketCapApi) { + Oep8TxDetailMapper oep8TxDetailMapper, TokenDailyAggregationMapper tokenDailyAggregationMapper, + RankingMapper rankingMapper, CoinMarketCapApi coinMarketCapApi, OepLogoMapper oepLogoMapper) { this.oep4Mapper = oep4Mapper; this.oep5Mapper = oep5Mapper; this.oep8Mapper = oep8Mapper; @@ -65,6 +55,7 @@ public TokenServiceImpl(Oep4Mapper oep4Mapper, Oep5Mapper oep5Mapper, Oep8Mapper this.tokenDailyAggregationMapper = tokenDailyAggregationMapper; this.rankingMapper = rankingMapper; this.coinMarketCapApi = coinMarketCapApi; + this.oepLogoMapper = oepLogoMapper; } @Override @@ -220,4 +211,17 @@ public void setParamsConfig(ParamsConfig paramsConfig) { }); } + + @Override + public ResponseBean queryOepLogos(String contractHash, int pageSize, int pageNumber) { + PageHelper.startPage(pageNumber, pageSize); + Example example = new Example(OepLogo.class); + example.and() + .andEqualTo("contractHash", contractHash); + example.orderBy("id").desc(); + List oepLogos = oepLogoMapper.selectByExample(example); + Long total = ((Page) oepLogos).getTotal(); + PageResponseBean responseBean = new PageResponseBean(oepLogos, total.intValue()); + return new ResponseBean(ErrorInfo.SUCCESS.code(), ErrorInfo.SUCCESS.desc(), responseBean); + } } diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/UserServiceImpl.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/UserServiceImpl.java new file mode 100644 index 00000000..68cdbd3e --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/UserServiceImpl.java @@ -0,0 +1,240 @@ +package com.github.ontio.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import com.github.ontio.config.ParamsConfig; +import com.github.ontio.core.asset.Sig; +import com.github.ontio.core.transaction.Transaction; +import com.github.ontio.crypto.Digest; +import com.github.ontio.mapper.AddressBlacklistMapper; +import com.github.ontio.mapper.UserAddressMapper; +import com.github.ontio.mapper.UserMapper; +import com.github.ontio.model.common.PageResponseBean; +import com.github.ontio.model.common.RedisKey; +import com.github.ontio.model.common.ResponseBean; +import com.github.ontio.model.dao.AddressBlacklist; +import com.github.ontio.model.dao.User; +import com.github.ontio.model.dao.UserAddress; +import com.github.ontio.model.dto.login.CallBackDto; +import com.github.ontio.model.dto.login.CallBackResponse; +import com.github.ontio.model.dto.login.QrCodeDto; +import com.github.ontio.service.IUserService; +import com.github.ontio.util.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * @author zhouq + * @version 1.0 + * @date 2020/3/24 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class UserServiceImpl implements IUserService { + + private static final String CACHEKEY_BLACKADDR = "blackAddress"; + private static final String SIGNATURE_PREFIX = "01"; + + private final UserAddressMapper userAddressMapper; + private final UserMapper userMapper; + private final ParamsConfig paramsConfig; + private final StringRedisTemplate redisTemplate; + private final AddressBlacklistMapper addressBlacklistMapper; + private final OntologySDKService sdkService; + + private LoadingCache> blackAddressCache = null; + + @Autowired + private void setCache() { + blackAddressCache = Caffeine.newBuilder() + .expireAfterWrite(5, TimeUnit.MINUTES) + .build(key -> { + List addressBlacklist = addressBlacklistMapper.selectAll(); + return addressBlacklist.stream().map(item -> item.getAddress()).collect(Collectors.toList()); + }); + } + + @Override + public ResponseBean queryWebQrCode() { + String qrCodeId = Helper.generateQrCodeId(); + redisTemplate.opsForValue().set(String.format(RedisKey.USERLOGIN_QRCODEID, qrCodeId), "", 2, TimeUnit.MINUTES); + Map rsMap = new HashMap<>(); + rsMap.put("ONTAuthScanProtocol", paramsConfig.loginQrCodeUrl + qrCodeId); + rsMap.put("Id", qrCodeId); + return Helper.successResult(rsMap); + } + + @Override + public QrCodeDto queryQrCode(String qrCodeId) { + QrCodeDto qrCodeDto = generateQrCode(qrCodeId); + return qrCodeDto; + } + + private QrCodeDto generateQrCode(String qrCodeId) { + QrCodeDto.QrCodeDataParamFunArg qrCodeDataParamFunArg = QrCodeDto.QrCodeDataParamFunArg.builder() + .name("message") + .value("") + .build(); + QrCodeDto.QrCodeDataParamFun qrCodeDataParamFun = QrCodeDto.QrCodeDataParamFun.builder() + .operation("signMessage") + .args(Arrays.asList(qrCodeDataParamFunArg)) + .build(); + QrCodeDto.QrCodeDataParamDetail qrCodeDataParamDetail = QrCodeDto.QrCodeDataParamDetail.builder() + .contractHash("0000000000000000000000000000000000000000") + .payer("") + .gasLimit(new BigDecimal("0")) + .gasPrice(new BigDecimal("0")) + .functions(Arrays.asList(qrCodeDataParamFun)) + .build(); + QrCodeDto.QrCodeDataParam qrCodeDataParam = QrCodeDto.QrCodeDataParam.builder() + .invokeConfig(qrCodeDataParamDetail) + .build(); + QrCodeDto.QrCodeData qrCodeData = QrCodeDto.QrCodeData.builder() + .action("signMessage") + .params(qrCodeDataParam) + .build(); + String signature = sdkService.signData2HexStr(JacksonUtil.beanToJSonStr(qrCodeData)); + + return QrCodeDto.mainNetLoginQrCode(qrCodeId, paramsConfig.IDENTITY_ONTID, signature, qrCodeData, paramsConfig.loginCallbackUrl, System.currentTimeMillis() + 2 * 60 * 1000L); + } + + + @Override + public ResponseBean queryLoginUserInfo(String qrCodeId) { + String token = redisTemplate.opsForValue().get(String.format(RedisKey.USERLOGIN_QRCODEID, qrCodeId)); + if (token == null) { + return Helper.successResult(ErrorInfo.QRCODE_EXPIRED.code()); + } else if ("".equals(token)) { + return Helper.successResult(ErrorInfo.NO_LOGIN_USERINFO.code()); + } + String ontId = JwtUtil.getClaim(token, ConstantParam.JWT_LOGINID).asString(); + User user = userMapper.selectByPrimaryKey(ontId); + //get last login time + Date lastLoginTime = user.getLastLoginTime(); + user.setLastLoginTime(new Date()); + userMapper.updateByPrimaryKeySelective(user); + user.setLastLoginTime(lastLoginTime); + //set token + HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); + resp.setHeader(ConstantParam.HTTPHEADER_TOKEN, token); + return Helper.successResult(user); + } + + + @Override + public CallBackResponse login(CallBackDto callBackDto) { + String ontId = callBackDto.getSigner(); + String signedTx = callBackDto.getSignedTx(); + String qrCodeId = callBackDto.getExtraData().getId(); + Boolean verifyFlag = verifySignature(ontId, signedTx); + if (!verifyFlag) { + return CallBackResponse.errorResponse(ErrorInfo.VERIFY_SIGN_FAILED.code()); + } + String redisValue = redisTemplate.opsForValue().get(String.format(RedisKey.USERLOGIN_QRCODEID, qrCodeId)); + if (redisValue == null) { + return CallBackResponse.errorResponse(ErrorInfo.QRCODE_EXPIRED.code()); + } + String token = JwtUtil.signToken(ontId); + redisTemplate.opsForValue().set(String.format(RedisKey.USERLOGIN_QRCODEID, qrCodeId), token, 60, TimeUnit.SECONDS); + + User user = userMapper.selectByPrimaryKey(ontId); + if (user == null) { + Date now = new Date(); + user = User.builder() + .ontId(ontId) + .userName("") + .email("") + .lastLoginTime(now) + .createTime(now) + .build(); + userMapper.insert(user); + } + return CallBackResponse.successResponse(new JSONObject()); + } + + private boolean verifySignature(String ontId, String signedTx) { + Transaction transaction = null; + try { + transaction = Transaction.deserializeFrom(com.github.ontio.common.Helper.hexToBytes(signedTx)); + } catch (IOException e) { + log.error("{} error...", Helper.currentMethod(), e); + return false; + } + byte[] sigBytes = transaction.sigs[0].sigData[0]; + String signature = com.github.ontio.common.Helper.toHexString(sigBytes); + if (!signature.startsWith(SIGNATURE_PREFIX)) { + signature = SIGNATURE_PREFIX + signature; + } + transaction.sigs = new Sig[0]; + String hex = transaction.toHexString(); + String tx = hex.substring(0, hex.length() - 2); + String data = com.github.ontio.common.Helper.toHexString(Digest.hash256(com.github.ontio.common.Helper.hexToBytes(tx))); + return sdkService.verifySignature(ontId, data, signature); + } + + + @Override + public ResponseBean queryUserAddresses(String ontId) { + UserAddress userAddress = UserAddress.builder() + .ontId(ontId) + .build(); + List userAddresses = userAddressMapper.select(userAddress); + PageResponseBean pageResponseBean = new PageResponseBean(userAddresses, userAddresses.size()); + return Helper.successResult(pageResponseBean); + } + + + @Override + public ResponseBean addOrUpdateUserAddresses(List userAddressList, String ontId) { + if (userAddressList.size() > paramsConfig.oneUserAddressCountLimit) { + //normal response can refresh token + return Helper.errorResult(ErrorInfo.ADDRESS_TOOMANY, false); + } + if (CollectionUtils.containsAny(blackAddressCache.get(CACHEKEY_BLACKADDR), userAddressList.stream().map(key -> key.getAddress()).collect(Collectors.toList()))) { + return Helper.errorResult(ErrorInfo.IN_BLACKADDRESS, false); + } + userAddressList.forEach(userAddress -> { + userAddress.setOntId(ontId); + }); + userAddressMapper.saveUserAddress(userAddressList); + return Helper.successResult(true); + } + + @Override + public ResponseBean delUserAddress(String address, String ontId) { + if (address.length() != 34 || !address.startsWith("A")) { + return Helper.errorResult(ErrorInfo.ADDRESS_FORMAT_INCORRECT, false); + } + UserAddress userAddress = UserAddress.builder() + .ontId(ontId) + .address(address) + .build(); + int count = userAddressMapper.delete(userAddress); + if (count == 0) { + return Helper.errorResult(ErrorInfo.ADDRESS_ONTID_UNMATCH, false); + } + return Helper.successResult(true); + } + + + @Override + public ResponseBean updateUser(User user) { + userMapper.updateByPrimaryKeySelective(user); + return Helper.successResult(true); + } +} diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ConstantParam.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ConstantParam.java index 792f8fc3..debc22f0 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ConstantParam.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ConstantParam.java @@ -172,5 +172,9 @@ public class ConstantParam { public static final String CONTRACTHASH_ONT = "0100000000000000000000000000000000000000"; + public static final String HTTPHEADER_TOKEN = "ont_exp_token"; + + public static final String JWT_LOGINID = "loginId"; + } diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ErrorInfo.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ErrorInfo.java index bfc6115e..f7d239e1 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ErrorInfo.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ErrorInfo.java @@ -88,6 +88,25 @@ public enum ErrorInfo { */ ALREADY_AUDITPASS(61011,"FAIL, already on shelves."), + QRCODE_EXPIRED(61012,"Qrcode expired."), + + NO_LOGIN_USERINFO(61013,"No login user info."), + + TOKEN_EXPIRED(61014,"Token expired."), + + TOKEN_UNMATCH(61015,"Token unmatch."), + + TOKEN_EMPTY(61016,"Token empty."), + + IN_BLACKADDRESS(61017,"Address in blacklist."), + + ADDRESS_TOOMANY(61018,"Too many addresses."), + + ADDRESS_ONTID_UNMATCH(61019,"Address unmatch ontid."), + + ADDRESS_FORMAT_INCORRECT(61020,"Address format incorrect."), + + @@ -116,6 +135,10 @@ public enum ErrorInfo { */ DB_ERROR(62005, "FAIL, db operate fail."), + VERIFY_SIGN_FAILED(62006,"Verify signature failed."), + + TX_ERROR(62007,"transaction error."), + /** * inner error diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/Helper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/Helper.java index b1646492..721dac81 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/Helper.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/Helper.java @@ -21,12 +21,14 @@ import com.github.ontio.mapper.BlockMapper; import com.github.ontio.model.common.OntIdEventEnum; +import com.github.ontio.model.common.ResponseBean; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.Base64; +import java.util.Random; /** * @author zhouq @@ -60,6 +62,28 @@ public static Boolean isNotEmptyAndNull(Object... params) { return !isEmptyOrNull(params); } + public static ResponseBean successResult(Object obj) { + return new ResponseBean(ErrorInfo.SUCCESS.code(), ErrorInfo.SUCCESS.desc(), obj); + } + + public static ResponseBean errorResult(ErrorInfo errorInfo, Object obj) { + return new ResponseBean(errorInfo.code(), errorInfo.desc(), obj); + } + + public static String generateQrCodeId() { + return String.valueOf(System.currentTimeMillis()) + getRandomString(5); + } + + public static String getRandomString(int length) { + String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + Random random = new Random(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < length; i++) { + int number = random.nextInt(62); + sb.append(str.charAt(number)); + } + return sb.toString(); + } /** * 判断时间范围是否超过一个月 @@ -133,6 +157,7 @@ public static String templateOntIdOperation(String inputStr) { /** * 判断redis的key是否属于REDIS_LONGEXPIRETIME_KEYLIST + * * @param redisKey * @return */ @@ -154,6 +179,7 @@ public static Boolean isBelongRedisLongExpireMapper(String redisKey) { /** * 判断redis的key是否属于REDIS_MEDIUMEXPIRETIME_KEYLIST + * * @param redisKey * @return */ @@ -221,7 +247,6 @@ public static String currentMethod() { } - /** * 根据base64后的图片数据生成本地文件 * diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/JwtUtil.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/JwtUtil.java new file mode 100644 index 00000000..543e4949 --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/JwtUtil.java @@ -0,0 +1,82 @@ +package com.github.ontio.util; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.interfaces.Claim; +import com.auth0.jwt.interfaces.DecodedJWT; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.Base64; +import java.util.Date; + +/** + * JAVA-JWT util + */ +@Component +@Slf4j +public class JwtUtil { + + private static String accessTokenExpireTime; + + private static String encryptJWTKey; + + @Value("${jwt.accessTokenExpireTime}") + public void setAccessTokenExpireTime(String tokenExpireTime) { + JwtUtil.accessTokenExpireTime = tokenExpireTime.trim(); + } + + @Value("${jwt.encryptJWTKey}") + public void setEncryptJWTKey(String jWTKey) { + JwtUtil.encryptJWTKey = jWTKey.trim(); + } + + + public static boolean verifyToken(String token) { + try { + String ontId = getClaim(token, ConstantParam.JWT_LOGINID).asString(); + String secret = preSecret(ontId); + Algorithm algorithm = Algorithm.HMAC256(secret); + JWTVerifier verifier = JWT.require(algorithm).build(); + DecodedJWT jwt = verifier.verify(token); + log.info("verifytoken jwt:{}", jwt.toString()); + } catch (Exception e) { + log.error("verifyToken error...{}", e.getMessage()); + return false; + } + return true; + } + + + public static Claim getClaim(String token, String claim) { + try { + DecodedJWT jwt = JWT.decode(token); + return jwt.getClaim(claim); + } catch (JWTDecodeException e) { + log.error("getClaim error...{}", e.getMessage()); + return null; + } + } + + + public static String signToken(String ontId) { + // ontId+JWT key + String secret = preSecret(ontId); + Date date = new Date(System.currentTimeMillis() + Long.parseLong(accessTokenExpireTime) * 1000); + Algorithm algorithm = Algorithm.HMAC256(secret); + return JWT.create() + .withClaim(ConstantParam.JWT_LOGINID, ontId) + .withExpiresAt(date) + .sign(algorithm); + } + + private static String preSecret(String ontId) { + String secret = ontId + new String(Base64.getDecoder().decode(encryptJWTKey)); + return secret; + } + + +} diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/OntologySDKService.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/OntologySDKService.java index 9dfcc7fa..f4a6baac 100644 --- a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/OntologySDKService.java +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/OntologySDKService.java @@ -24,9 +24,11 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.github.ontio.OntSdk; +import com.github.ontio.account.Account; import com.github.ontio.common.Address; import com.github.ontio.common.Helper; import com.github.ontio.config.ParamsConfig; +import com.github.ontio.core.DataSignature; import com.github.ontio.core.payload.InvokeWasmCode; import com.github.ontio.core.transaction.Transaction; import com.github.ontio.smartcontract.neovm.abi.BuildParams; @@ -295,4 +297,56 @@ private OntSdk getOep5OntSdk(String codeHash) { return wm; } + + /** + * verify signature + * + * @param ontId + * @param origDataStr + * @param signatureStr + * @return + */ + public boolean verifySignature(String ontId, String origDataStr, String signatureStr) { + try { + Boolean verify = Boolean.FALSE; + OntSdk ontSdk = OntSdk.getInstance(); + ontSdk.setRestful(paramsConfig.MASTERNODE_RESTFUL_URL); + String issuerDdo = ontSdk.nativevm().ontId().sendGetDDO(ontId); + + JSONArray owners = JSONObject.parseObject(issuerDdo).getJSONArray("Owners"); + for (int i = 0; i < owners.size(); ++i) { + String pubkeyStr = owners.getJSONObject(i).getString("Value"); + Account account = new Account(false, Helper.hexToBytes(pubkeyStr)); + verify = account.verifySignature(Helper.hexToBytes(origDataStr), Helper.hexToBytes(signatureStr)); + if (verify) { + break; + } + } + return verify; + } catch (Exception e) { + log.error("{} error...", com.github.ontio.util.Helper.currentMethod(), e); + } + return false; + } + + /** + * sign + * + * @param origData + * @return + */ + public String signData2HexStr(String origData) { + try { + OntSdk ontSdk = OntSdk.getInstance(); + ontSdk.openWalletFile("account.json"); + Account account = ontSdk.getWalletMgr().getAccount(paramsConfig.IDENTITY_ONTID, paramsConfig.IDENTITY_PASSWORD, Base64.getDecoder().decode(paramsConfig.IDENTITY_SALT)); + DataSignature sign = new DataSignature(ontSdk.defaultSignScheme, account, origData.getBytes()); + String sigdata = Helper.toHexString(sign.signature()); + return sigdata; + } catch (Exception e) { + log.error("{} error...", com.github.ontio.util.Helper.currentMethod(), e); + } + return ""; + } + } diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/TxDateSerializer.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/TxDateSerializer.java new file mode 100644 index 00000000..06dd2b88 --- /dev/null +++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/TxDateSerializer.java @@ -0,0 +1,23 @@ +package com.github.ontio.util; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; +import java.util.Date; + +/** + * @author zhouq + * @version 1.0 + * @date 2019/7/25 + */ +public class TxDateSerializer extends JsonSerializer { + + @Override + public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { + jsonGenerator.writeNumber(date.getTime() / 1000L); + } + +} diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.38__tbl_tx_detail_index.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.38__tbl_tx_detail_index.sql new file mode 100644 index 00000000..ffb9d4a1 --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.38__tbl_tx_detail_index.sql @@ -0,0 +1,16 @@ +-- ---------------------------- +-- Table structure for tbl_tx_detail_index +-- ---------------------------- +DROP TABLE IF EXISTS `tbl_tx_detail_index`; +CREATE TABLE `tbl_tx_detail_index` ( + `address` CHAR(80) NOT NULL DEFAULT '' COMMENT '交易地址', + `desc_block_height` INT(11) NOT NULL COMMENT '倒序区块高度', + `tx_hash` CHAR(64) NOT NULL DEFAULT '' COMMENT '交易hash', + `tx_index` INT(11) NOT NULL COMMENT '该event在交易eventlog里的索引', + `called_contract_hash` CHAR(40) NOT NULL DEFAULT '' COMMENT '该交易真正调用的合约hash', + `tx_time` INT(11) NOT NULL COMMENT '交易时间戳', + `asset_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '交易资产名', + `tx_direction` TINYINT NOT NULL COMMENT '交易方向 0:FROM 1:TO 2:BOTH', + PRIMARY KEY (`address`, `desc_block_height`, `tx_hash`, `tx_index`), + KEY `idx_address_contract_hash`(`address`, `called_contract_hash`) +) ENGINE = InnoDB DEFAULT CHARSET = utf8; diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.39__tbl_oep5_tx_detail.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.39__tbl_oep5_tx_detail.sql new file mode 100644 index 00000000..a34a174c --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.39__tbl_oep5_tx_detail.sql @@ -0,0 +1,5 @@ +-- ---------------------------- +-- Change index structure for tbl_oep5_tx_detail +-- ---------------------------- +DROP INDEX idx_called_contract_hash ON tbl_oep5_tx_detail; +CREATE INDEX idx_called_contract_hash_block_height ON tbl_oep5_tx_detail(`called_contract_hash`, `block_height`); diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.40__tbl_tx_eventlog.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.40__tbl_tx_eventlog.sql new file mode 100644 index 00000000..c810eeae --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.40__tbl_tx_eventlog.sql @@ -0,0 +1,5 @@ +-- ---------------------------- +-- Change index structure for tbl_tx_eventlog +-- ---------------------------- +DROP INDEX idx_called_contract_hash ON tbl_tx_eventlog; +CREATE INDEX idx_called_contract_hash_block_height ON tbl_tx_eventlog (`called_contract_hash`, `block_height`); diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.41__tbl_oep4_tx_detail.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.41__tbl_oep4_tx_detail.sql new file mode 100644 index 00000000..951ab650 --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.41__tbl_oep4_tx_detail.sql @@ -0,0 +1,5 @@ +-- ---------------------------- +-- Change index structure for tbl_oep4_tx_detail +-- ---------------------------- +DROP INDEX idx_called_contract_hash ON tbl_oep4_tx_detail; +CREATE INDEX idx_called_contract_hash_block_height ON tbl_oep4_tx_detail (`called_contract_hash`, `block_height`); \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.42__tbl_address_blacklist.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.42__tbl_address_blacklist.sql new file mode 100644 index 00000000..10dd4ba0 --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.42__tbl_address_blacklist.sql @@ -0,0 +1,10 @@ +-- ---------------------------- +-- Table structure for tbl_address_blacklist +-- ---------------------------- +DROP TABLE IF EXISTS `tbl_address_blacklist`; +CREATE TABLE `tbl_address_blacklist` ( + `address` varchar(255) NOT NULL DEFAULT '', + `note` varchar(255) NOT NULL DEFAULT '' COMMENT '备注', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`address`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.43__tbl_user.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.43__tbl_user.sql new file mode 100644 index 00000000..54ef3536 --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.43__tbl_user.sql @@ -0,0 +1,12 @@ +-- ---------------------------- +-- Table structure for tbl_user +-- ---------------------------- +DROP TABLE IF EXISTS `tbl_user`; +CREATE TABLE `tbl_user` ( + `ont_id` varchar(255) NOT NULL DEFAULT '' COMMENT 'ONT ID', + `user_name` varchar(255) NOT NULL DEFAULT '' COMMENT '用户名', + `email` varchar(255) NOT NULL DEFAULT '' COMMENT '邮箱', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', + `last_login_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '上次登录时间', + PRIMARY KEY (`ont_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.44__tbl_user_address.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.44__tbl_user_address.sql new file mode 100644 index 00000000..5e3ee632 --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.44__tbl_user_address.sql @@ -0,0 +1,16 @@ +-- ---------------------------- +-- Table structure for tbl_user_address +-- ---------------------------- +DROP TABLE IF EXISTS `tbl_user_address`; +CREATE TABLE `tbl_user_address` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ont_id` varchar(255) NOT NULL DEFAULT '' COMMENT 'ONT ID', + `address` varchar(255) NOT NULL DEFAULT '' COMMENT '地址', + `note` varchar(255) NOT NULL DEFAULT '' COMMENT '地址备注', + `strategy` int(11) NOT NULL DEFAULT '0' COMMENT '监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金', + `include_oep_token` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1:监听oep资产 0:不监听oep资产', + PRIMARY KEY (`id`), + UNIQUE KEY `unq_ontid_address` (`address`,`ont_id`), + KEY `fkey_ontId` (`ont_id`), + CONSTRAINT `fkey_ontId` FOREIGN KEY (`ont_id`) REFERENCES `tbl_user` (`ont_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.45__tbl_oep_logo.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.45__tbl_oep_logo.sql new file mode 100644 index 00000000..9be93cd6 --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.45__tbl_oep_logo.sql @@ -0,0 +1,15 @@ +-- ---------------------------- +-- Table structure for tbl_oep_logo +-- ---------------------------- +DROP TABLE IF EXISTS `tbl_oep_logo`; +CREATE TABLE `tbl_oep_logo` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `contract_hash` varchar(255) NOT NULL DEFAULT '' COMMENT '合约hash', + `type` varchar(255) NOT NULL DEFAULT '' COMMENT 'oep5,oep8', + `token_id` varchar(255) NOT NULL DEFAULT '' COMMENT '合约token id', + `logo` varchar(255) NOT NULL DEFAULT '' COMMENT 'logo链接', + `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'token名称', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `unq_contracthash_tokenid` (`contract_hash`,`token_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.46__tbl_user.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.46__tbl_user.sql new file mode 100644 index 00000000..16df1f2d --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.46__tbl_user.sql @@ -0,0 +1 @@ +ALTER TABLE tbl_user MODIFY last_login_time datetime NOT NULL COMMENT '上次登录时间'; diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.47__tbl_tx_detail_index.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.47__tbl_tx_detail_index.sql new file mode 100644 index 00000000..06ada90e --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.47__tbl_tx_detail_index.sql @@ -0,0 +1,2 @@ +DROP INDEX idx_address_contract_hash ON tbl_tx_detail_index; +CREATE INDEX idx_contract_hash_block_height ON tbl_tx_detail_index(`called_contract_hash`, `desc_block_height`); \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.48__tbl_oep5_tx_detail_index.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.48__tbl_oep5_tx_detail_index.sql new file mode 100644 index 00000000..7ffc4e31 --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.48__tbl_oep5_tx_detail_index.sql @@ -0,0 +1 @@ +CREATE INDEX idx_called_contract_hash_tx_hash ON tbl_oep5_tx_detail(`called_contract_hash`, `tx_hash`); diff --git a/back-end-projects/Explorer/src/main/resources/generator/generatorConfig.xml b/back-end-projects/Explorer/src/main/resources/generator/generatorConfig.xml index 2bb304d6..fb5b44e9 100644 --- a/back-end-projects/Explorer/src/main/resources/generator/generatorConfig.xml +++ b/back-end-projects/Explorer/src/main/resources/generator/generatorConfig.xml @@ -18,7 +18,7 @@ + password="zaq12wsx"> @@ -41,7 +41,7 @@ - + + +
+
diff --git a/back-end-projects/Explorer/src/main/resources/mapper/AddressBlacklistMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/AddressBlacklistMapper.xml new file mode 100644 index 00000000..97596a30 --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/mapper/AddressBlacklistMapper.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/resources/mapper/Oep5TxDetailMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/Oep5TxDetailMapper.xml index fc48779d..8cca448e 100644 --- a/back-end-projects/Explorer/src/main/resources/mapper/Oep5TxDetailMapper.xml +++ b/back-end-projects/Explorer/src/main/resources/mapper/Oep5TxDetailMapper.xml @@ -51,30 +51,26 @@ diff --git a/back-end-projects/Explorer/src/main/resources/mapper/OepLogoMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/OepLogoMapper.xml new file mode 100644 index 00000000..07972d54 --- /dev/null +++ b/back-end-projects/Explorer/src/main/resources/mapper/OepLogoMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/back-end-projects/Explorer/src/main/resources/mapper/TxDetailMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/TxDetailMapper.xml index d15a60dc..ba3da1f4 100644 --- a/back-end-projects/Explorer/src/main/resources/mapper/TxDetailMapper.xml +++ b/back-end-projects/Explorer/src/main/resources/mapper/TxDetailMapper.xml @@ -107,7 +107,6 @@ AND asset_name = #{assetName} - AND event_type IN (2, 3) ORDER BY desc_block_height, tx_hash, tx_index LIMIT #{startIndex}, #{pageSize} ) idx ON idx.hash = d.tx_hash @@ -134,7 +133,6 @@ AND asset_name = #{assetName} - AND event_type IN (2, 3) ORDER BY desc_block_height, tx_hash, tx_index ) idx ON idx.hash = d.tx_hash AND idx.`index` = d.tx_index diff --git a/back-end-projects/Explorer/src/main/resources/mapper/TxEventLogMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/TxEventLogMapper.xml index ae3532ee..9a98535b 100644 --- a/back-end-projects/Explorer/src/main/resources/mapper/TxEventLogMapper.xml +++ b/back-end-projects/Explorer/src/main/resources/mapper/TxEventLogMapper.xml @@ -42,15 +42,16 @@ + SELECT if(max(id) IS NULL, 0, max(id)) + FROM tbl_tx_eventlog; + \ No newline at end of file diff --git a/back-end-projects/OntSynHandler/src/main/resources/mapper/UserAddressMapper.xml b/back-end-projects/OntSynHandler/src/main/resources/mapper/UserAddressMapper.xml new file mode 100644 index 00000000..067b2aac --- /dev/null +++ b/back-end-projects/OntSynHandler/src/main/resources/mapper/UserAddressMapper.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/back-end-projects/OntSynHandler/src/main/resources/mapper/UserMapper.xml b/back-end-projects/OntSynHandler/src/main/resources/mapper/UserMapper.xml new file mode 100644 index 00000000..99b58702 --- /dev/null +++ b/back-end-projects/OntSynHandler/src/main/resources/mapper/UserMapper.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file