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 java.io.IOException; 023import java.io.StringReader; 024import java.nio.charset.StandardCharsets; 025import java.util.Calendar; 026import java.util.Date; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030import javax.annotation.Nullable; 031import org.apache.commons.codec.binary.Base64; 032import org.apache.commons.io.IOUtils; 033import org.apache.commons.lang.StringUtils; 034import org.sonar.api.utils.DateUtils; 035 036/** 037 * SonarSource license. This class aims to extract metadata but not to validate or - of course - 038 * to generate license 039 * 040 * @since 3.0 041 */ 042public final class License { 043 private String product; 044 private String organization; 045 private String expirationDate; 046 private String type; 047 private String server; 048 private Map<String, String> additionalProperties; 049 050 private License(Map<String, String> properties) { 051 this.additionalProperties = new HashMap<>(properties); 052 product = StringUtils.defaultString(get("Product", properties), get("Plugin", properties)); 053 organization = StringUtils.defaultString(get("Organisation", properties), get("Name", properties)); 054 expirationDate = StringUtils.defaultString(get("Expiration", properties), get("Expires", properties)); 055 type = get("Type", properties); 056 server = get("Server", properties); 057 // SONAR-4340 Don't expose Digest and Obeo properties 058 additionalProperties.remove("Digest"); 059 additionalProperties.remove("Obeo"); 060 } 061 062 private String get(String key, Map<String, String> properties) { 063 additionalProperties.remove(key); 064 return properties.get(key); 065 } 066 067 /** 068 * Get additional properties available on this license (like threshold conditions) 069 * @since 3.6 070 */ 071 public Map<String, String> additionalProperties() { 072 return additionalProperties; 073 } 074 075 @Nullable 076 public String getProduct() { 077 return product; 078 } 079 080 @Nullable 081 public String getOrganization() { 082 return organization; 083 } 084 085 @Nullable 086 public String getExpirationDateAsString() { 087 return expirationDate; 088 } 089 090 @Nullable 091 public Date getExpirationDate() { 092 return DateUtils.parseDateQuietly(expirationDate); 093 } 094 095 public boolean isExpired() { 096 return isExpired(new Date()); 097 } 098 099 boolean isExpired(Date now) { 100 Date date = getExpirationDate(); 101 if (date == null) { 102 return false; 103 } 104 // SONAR-6079 include last day 105 Calendar cal = Calendar.getInstance(); 106 cal.setTime(date); 107 cal.add(Calendar.DAY_OF_MONTH, 1); 108 cal.add(Calendar.SECOND, -1); 109 return now.after(cal.getTime()); 110 } 111 112 @Nullable 113 public String getType() { 114 return type; 115 } 116 117 @Nullable 118 public String getServer() { 119 return server; 120 } 121 122 public static License readBase64(String base64) { 123 return readPlainText(new String(Base64.decodeBase64(base64.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8)); 124 } 125 126 static License readPlainText(String data) { 127 Map<String, String> props = new HashMap<>(); 128 try { 129 List<String> lines = IOUtils.readLines(new StringReader(data)); 130 for (String line : lines) { 131 if (StringUtils.isNotBlank(line) && line.indexOf(':') > 0) { 132 String key = StringUtils.substringBefore(line, ":"); 133 String value = StringUtils.substringAfter(line, ":"); 134 props.put(StringUtils.trimToEmpty(key), StringUtils.trimToEmpty(value)); 135 } 136 } 137 138 } catch (IOException e) { 139 // silently ignore 140 } 141 return new License(props); 142 } 143}