/**
 * Copyright (c) 2015-2020, Michael Yang 杨福海 (fuhai999@gmail.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.jboot.support.jwt;

import com.jfinal.kit.JsonKit;
import io.jboot.Jboot;
import io.jboot.exception.JbootException;
import io.jboot.utils.StrUtil;
import io.jsonwebtoken.*;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Michael Yang 杨福海 （fuhai999@gmail.com）
 * @version V1.0
 * @Package io.jboot.web.jwt
 */
public class JwtManager {

    private static final JwtManager me = new JwtManager();

    public static JwtManager me() {
        return me;
    }

    private ThreadLocal<Map> jwtThreadLocal = new ThreadLocal<>();

    public void holdJwts(Map map) {
        jwtThreadLocal.set(map);
    }

    public void releaseJwts() {
        jwtThreadLocal.remove();
    }

    public <T> T getPara(String key) {
        Map map = jwtThreadLocal.get();
        return map == null ? null : (T) map.get(key);
    }

    public Map getParas() {
        return jwtThreadLocal.get();
    }

    public String getHttpHeaderName() {
        return getConfig().getHttpHeaderName();
    }

    public String getHttpParameterKey() {
        return getConfig().getHttpParameterKey();
    }

    public Map parseJwtToken(String token) {
        SecretKey secretKey = generalKey();
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(token).getBody();

            String jsonString = claims.getSubject();

            if (StrUtil.isBlank(jsonString)) {
                return null;
            }
            return JsonKit.parse(jsonString, HashMap.class);

        } catch (SignatureException | MalformedJwtException e) {
            // don't trust the JWT!
            // jwt 签名错误或解析错误，可能是伪造的，不能相信
        } catch (ExpiredJwtException e) {
            // jwt 已经过期
        } catch (Throwable ex) {
            //其他错误
        }

        return null;
    }

    public String createJwtToken(Map map) {

        if (!getConfig().isConfigOk()) {
            throw new JbootException("can not create jwt, please config jboot.web.jwt.secret in jboot.properties.");
        }

        SecretKey secretKey = generalKey();

        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        map.put(JwtInterceptor.ISUUED_AT, nowMillis);
        String subject = JsonKit.toJson(map);

        JwtBuilder builder = Jwts.builder()
                .setIssuedAt(now)
                .setSubject(subject)
                .signWith(signatureAlgorithm, secretKey);

        if (getConfig().getValidityPeriod() > 0) {
            long expMillis = nowMillis + getConfig().getValidityPeriod();
            builder.setExpiration(new Date(expMillis));
        }

        return builder.compact();
    }


    private SecretKey generalKey() {
        byte[] encodedKey = DatatypeConverter.parseBase64Binary(getConfig().getSecret());
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    private JwtConfig config;

    public JwtConfig getConfig() {
        if (config == null) {
            config = Jboot.config(JwtConfig.class);
        }
        return config;
    }


}

@@ -696,16 +696,43 @@
 sonKit;%0A
+import com.jfinal.log.Log;%0A
 import i
@@ -1218,16 +1218,81 @@
 nager();
+%0A    private static final Log LOG = Log.getLog(JwtManager.class);
 %0A%0A    pu
@@ -2264,25 +2264,24 @@
 tSubject();%0A
-%0A
             
@@ -2294,16 +2294,19 @@
 rUtil.is
+Not
 Blank(js
@@ -2326,47 +2326,8 @@
     
-            return null;%0A            %7D%0A
     
@@ -2379,24 +2379,37 @@
 Map.class);%0A
+            %7D
 %0A        %7D c
@@ -2539,16 +2539,66 @@
 %E9%80%A0%E7%9A%84%EF%BC%8C%E4%B8%8D%E8%83%BD%E7%9B%B8%E4%BF%A1%0A
+            LOG.error(%22do not trast the jwt!%22,e);%0A
         
@@ -2667,51 +2667,159 @@
     
-%7D catch (Throwable ex) %7B%0A            //%E5%85%B6%E4%BB%96%E9%94%99%E8%AF%AF
+    LOG.error(%22jwt is expired!%22,e);%0A        %7D catch (Throwable ex) %7B%0A            //%E5%85%B6%E4%BB%96%E9%94%99%E8%AF%AF%0A            LOG.error(%22jwt parseJwtToken error, return null.%22);
 %0A   

add print jwt parse error log