001/* 002 * SonarQube 003 * Copyright (C) 2009-2017 SonarSource SA 004 * mailto:info AT sonarsource DOT com 005 * 006 * This program is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.config; 021 022import com.google.common.annotations.VisibleForTesting; 023import java.io.IOException; 024import java.io.StringReader; 025import java.nio.charset.StandardCharsets; 026import java.util.Calendar; 027import java.util.Date; 028import java.util.HashMap; 029import java.util.List; 030import java.util.Map; 031import javax.annotation.Nullable; 032import org.apache.commons.codec.binary.Base64; 033import org.apache.commons.io.IOUtils; 034import org.apache.commons.lang.StringUtils; 035import org.sonar.api.utils.DateUtils; 036 037/** 038 * SonarSource license. This class aims to extract metadata but not to validate or - of course - 039 * to generate license 040 * 041 * @since 3.0 042 */ 043public final class License { 044 private String product; 045 private String organization; 046 private String expirationDate; 047 private String type; 048 private String server; 049 private Map<String, String> additionalProperties; 050 051 private License(Map<String, String> properties) { 052 this.additionalProperties = new HashMap<>(properties); 053 product = StringUtils.defaultString(get("Product", properties), get("Plugin", properties)); 054 organization = StringUtils.defaultString(get("Organisation", properties), get("Name", properties)); 055 expirationDate = StringUtils.defaultString(get("Expiration", properties), get("Expires", properties)); 056 type = get("Type", properties); 057 server = get("Server", properties); 058 // SONAR-4340 Don't expose Digest and Obeo properties 059 additionalProperties.remove("Digest"); 060 additionalProperties.remove("Obeo"); 061 } 062 063 private String get(String key, Map<String, String> properties) { 064 additionalProperties.remove(key); 065 return properties.get(key); 066 } 067 068 /** 069 * Get additional properties available on this license (like threshold conditions) 070 * @since 3.6 071 */ 072 public Map<String, String> additionalProperties() { 073 return additionalProperties; 074 } 075 076 @Nullable 077 public String getProduct() { 078 return product; 079 } 080 081 @Nullable 082 public String getOrganization() { 083 return organization; 084 } 085 086 @Nullable 087 public String getExpirationDateAsString() { 088 return expirationDate; 089 } 090 091 @Nullable 092 public Date getExpirationDate() { 093 return DateUtils.parseDateQuietly(expirationDate); 094 } 095 096 public boolean isExpired() { 097 return isExpired(new Date()); 098 } 099 100 @VisibleForTesting 101 boolean isExpired(Date now) { 102 Date date = getExpirationDate(); 103 if (date == null) { 104 return false; 105 } 106 // SONAR-6079 include last day 107 Calendar cal = Calendar.getInstance(); 108 cal.setTime(date); 109 cal.add(Calendar.DAY_OF_MONTH, 1); 110 cal.add(Calendar.SECOND, -1); 111 return now.after(cal.getTime()); 112 } 113 114 @Nullable 115 public String getType() { 116 return type; 117 } 118 119 @Nullable 120 public String getServer() { 121 return server; 122 } 123 124 public static License readBase64(String base64) { 125 return readPlainText(new String(Base64.decodeBase64(base64.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8)); 126 } 127 128 @VisibleForTesting 129 static License readPlainText(String data) { 130 Map<String, String> props = new HashMap<>(); 131 try { 132 List<String> lines = IOUtils.readLines(new StringReader(data)); 133 for (String line : lines) { 134 if (StringUtils.isNotBlank(line) && line.indexOf(':') > 0) { 135 String key = StringUtils.substringBefore(line, ":"); 136 String value = StringUtils.substringAfter(line, ":"); 137 props.put(StringUtils.trimToEmpty(key), StringUtils.trimToEmpty(value)); 138 } 139 } 140 141 } catch (IOException e) { 142 // silently ignore 143 } 144 return new License(props); 145 } 146}