本文整理汇总了Java中org.shredzone.acme4j.Authorization类的典型用法代码示例。如果您正苦于以下问题:Java Authorization类的具体用法?Java Authorization怎么用?Java Authorization使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
Authorization类属于org.shredzone.acme4j包,在下文中一共展示了Authorization类的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Java代码示例。
示例1: writeAuthorizationList
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
boolean writeAuthorizationList(List<Authorization> authorizationList) {
try {
List<String> authorizationLocationList = new LinkedList<>();
for(Authorization authorization : authorizationList){
authorizationLocationList.add(authorization.getLocation().toString());
}
IOManager.writeString(AUTHORIZATION_FILE_PATH,
getGson().toJson(authorizationLocationList, listOfAuthorizationLocationsObject));
} catch (IOException e) {
LOG.error("Cannot write authorization list to file: " + AUTHORIZATION_FILE_PATH
+ "\n Please check permissions of the file.", e);
return false;
}
return true;
}
开发者ID:porunov,项目名称:acme_client,代码行数:18,代码来源:AuthorizationCommand.java
示例2: getDomains
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
HashSet<String> getDomains(List<Authorization> authorizationList){
HashSet<String> domains;
if(getParameters().getDomains() == null){
domains = new HashSet<>();
for (Authorization authorization : authorizationList) {
try {
domains.add(authorization.getDomain());
}catch (Exception e){
LOG.warn("Cannot retrieve domain from authorization: "+authorization.getLocation(), e);
}
}
}else {
domains = new HashSet<>(getParameters().getDomains());
}
return domains;
}
开发者ID:porunov,项目名称:acme_client,代码行数:17,代码来源:AuthorizationCommand.java
示例3: nextHasNextTest
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Test unusual {@link Iterator#next()} and {@link Iterator#hasNext()} usage.
*/
@Test
public void nextHasNextTest() throws IOException {
List<URL> result = new ArrayList<>();
Iterator<Authorization> it = createIterator(pageURLs.get(0));
assertThat(it.hasNext(), is(true));
assertThat(it.hasNext(), is(true));
// don't try this at home, kids...
try {
for (;;) {
result.add(it.next().getLocation());
}
} catch (NoSuchElementException ex) {
assertThat(it.hasNext(), is(false));
assertThat(it.hasNext(), is(false));
}
assertThat(result, is(equalTo(resourceURLs)));
}
开发者ID:shred,项目名称:acme4j,代码行数:24,代码来源:ResourceIteratorTest.java
示例4: ChallengeManager
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
public ChallengeManager(Authorization authorization, String type, Session session) throws AcmeException {
this.challenge = authorization.findChallenge(type);
if (this.challenge == null) throw new AcmeException();
try {
challenge.rebind(session);
} catch (Exception ex) {
LOG.warn("Can not rebind challenge: " + challenge.getLocation() + " to session: " +
session.getServerUri().toString(), ex);
}
}
开发者ID:porunov,项目名称:acme_client,代码行数:11,代码来源:ChallengeManager.java
示例5: commandExecution
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
@Override
public void commandExecution() {
List<String> failedDomains = new LinkedList<>();
List<Authorization> authorizationList = new LinkedList<>();
for (String domain : getParameters().getDomains()) {
try {
AuthorizationManager authorizationManagement = new AuthorizationManager(
registrationManagement.getRegistration(), domain);
authorizationList.add(authorizationManagement.getAuthorization());
LOG.info("Authorization created: "+authorizationManagement.getAuthorization().getLocation());
writeChallengeByAuthorization(authorizationManagement);
} catch (Exception ex) {
LOG.error("Cannot authorize domain: " + domain + "\n" +
"It will be skipped", ex);
error = true;
failedDomains.add(domain);
}
}
List<Authorization> savedAuthorizations = getNotExpiredAuthorizations();
if (savedAuthorizations != null) {
authorizationList.addAll(savedAuthorizations);
}
error = error || !writeAuthorizationList(authorizationList);
if (failedDomains.size() > 0) {
JsonElement failedDomainsJsonElement = getGson().toJsonTree(failedDomains, new TypeToken<List<String>>() {
}.getType());
result.add("failed_domains", failedDomainsJsonElement);
error=true;
}
}
开发者ID:porunov,项目名称:acme_client,代码行数:35,代码来源:AuthorizeDomainsCommand.java
示例6: commandExecution
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
@Override
public void commandExecution() {
List<Authorization> allAuthrizationsList = getNotExpiredAuthorizations();
if (allAuthrizationsList == null) {
LOG.error("Cannot read file: " +
AUTHORIZATION_FILE_PATH);
error = true;
return;
}
List<String> failedAuthorizations = new LinkedList<>();
List<Authorization> authorizationList = new LinkedList<>();
for (Authorization authorization : allAuthrizationsList) {
if (getParameters().getDomains() == null || getParameters().getDomains().contains(authorization.getDomain())) {
try {
authorization.deactivate();
} catch (AcmeException e) {
LOG.error("Cannot deactivate authorization: "+authorization.getLocation().toString(), e);
failedAuthorizations.add(authorization.getLocation().toString());
error = true;
}
} else {
authorizationList.add(authorization);
}
}
error = error || !writeAuthorizationList(authorizationList);
if (failedAuthorizations.size() > 0) {
JsonElement failedDomainsJsonElement = getGson().toJsonTree(failedAuthorizations, new TypeToken<List<String>>() {
}.getType());
result.add("failed_authorizations", failedDomainsJsonElement);
error=true;
}
}
开发者ID:porunov,项目名称:acme_client,代码行数:39,代码来源:DeactivateDomainsAuthorizationCommand.java
示例7: updateAuth
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Safely updates the authorization, catching checked exceptions.
*
* @param auth
* {@link Authorization} to update
*/
protected void updateAuth(Authorization auth) {
try {
auth.update();
} catch (AcmeException ex) {
throw new AcmeLazyLoadingException(auth, ex);
}
}
开发者ID:shred,项目名称:acme4j,代码行数:14,代码来源:PebbleITBase.java
示例8: updateAuth
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Safely updates the authorization, catching checked exceptions.
*
* @param auth
* {@link Authorization} to update
*/
private void updateAuth(Authorization auth) {
try {
auth.update();
} catch (AcmeException ex) {
throw new AcmeLazyLoadingException(auth, ex);
}
}
开发者ID:shred,项目名称:acme4j,代码行数:14,代码来源:OrderTlsSniIT.java
示例9: nullTest
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Test if the {@link ResourceIterator} handles a {@code null} start URL.
*/
@Test(expected = NoSuchElementException.class)
public void nullTest() throws IOException {
Iterator<Authorization> it = createIterator(null);
assertThat(it, not(nullValue()));
assertThat(it.hasNext(), is(false));
it.next(); // throws NoSuchElementException
}
开发者ID:shred,项目名称:acme4j,代码行数:12,代码来源:ResourceIteratorTest.java
示例10: iteratorTest
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Test if the {@link ResourceIterator} returns all objects in the correct order.
*/
@Test
public void iteratorTest() throws IOException {
List<URL> result = new ArrayList<>();
Iterator<Authorization> it = createIterator(pageURLs.get(0));
while (it.hasNext()) {
result.add(it.next().getLocation());
}
assertThat(result, is(equalTo(resourceURLs)));
}
开发者ID:shred,项目名称:acme4j,代码行数:15,代码来源:ResourceIteratorTest.java
示例11: removeTest
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Test that {@link Iterator#remove()} fails.
*/
@Test(expected = UnsupportedOperationException.class)
public void removeTest() throws IOException {
Iterator<Authorization> it = createIterator(pageURLs.get(0));
it.next();
it.remove(); // throws UnsupportedOperationException
}
开发者ID:shred,项目名称:acme4j,代码行数:10,代码来源:ResourceIteratorTest.java
示例12: authorize
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
private void authorize(Registration reg, String domain) throws AcmeException, FileNotFoundException, IOException {
messages.add("authorizing domain: " + domain, LOG);
Authorization auth = reg.authorizeDomain(domain);
messages.add("find http challenge", LOG);
Http01Challenge challenge1 = auth.findChallenge(Http01Challenge.TYPE);
if (challenge1 == null) {
throw new AcmeException("Found no " + Http01Challenge.TYPE + " challenge, don't know what to do...");
}
messages.add("saving challenge request", LOG);
try (FileOutputStream fos = new FileOutputStream(new File(challengePath, challenge1.getToken()))) {
fos.write(challenge1.getAuthorization().getBytes(StandardCharsets.UTF_8));
}
Challenge challenge = challenge1;
if (challenge.getStatus() == Status.VALID) {
messages.add("challenge already successeded", LOG);
return;
}
messages.add("trigger challenge", LOG);
challenge.trigger();
// Poll for the challenge to complete.
try {
long retryTimeout = INITIAL_RETRY;
while (challenge.getStatus() != Status.VALID) {
// Did the authorization fail?
if (challenge.getStatus() == Status.INVALID) {
messages.add("Authorization failed: " + challenge.getError().getDetail());
throw new AcmeException("Challenge failed...");
}
Thread.sleep(retryTimeout);
try {
messages.add("update challenge", LOG);
challenge.update();
} catch (AcmeRetryAfterException e) {
retryTimeout = e.getRetryAfter().toEpochMilli() - System.currentTimeMillis();
messages.add("not ready. retry after: " + retryTimeout + " millis", LOG);
}
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
// All reattempts are used up and there is still no valid authorization?
if (challenge.getStatus() != Status.VALID) {
throw new AcmeException("Failed to pass the challenge for domain " + domain + ", ... Giving up.");
}
}
开发者ID:dernasherbrezon,项目名称:r2cloud,代码行数:51,代码来源:AcmeClient.java
示例13: AuthorizationManager
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
public AuthorizationManager(Session session, URI authUri) {
this.authorization = Authorization.bind(session, authUri);
}
开发者ID:porunov,项目名称:acme_client,代码行数:4,代码来源:AuthorizationManager.java
示例14: getAuthorization
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
public Authorization getAuthorization() {
return this.authorization;
}
开发者ID:porunov,项目名称:acme_client,代码行数:4,代码来源:AuthorizationManager.java
示例15: commandExecution
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
@Override
public void commandExecution() {
List<Authorization> authorizationList = getNotExpiredAuthorizations();
if (authorizationList == null) {
LOG.error("Cannot read file: " +
AUTHORIZATION_FILE_PATH);
error = true;
return;
}
HashSet<String> domains = getDomains(authorizationList);
HashSet<String> authorizedDomains = new HashSet<>();
for (Authorization authorization : authorizationList) {
authorizedDomains.add(authorization.getDomain());
if (domains.contains(authorization.getDomain())) {
try {
writeChallengeByAuthorization(new AuthorizationManager(authorization));
domains.remove(authorization.getDomain());
} catch (Exception e) {
LOG.warn("Cannot get challenge for authorization: " + authorization.getLocation()
+ "\nDomain: " + authorization.getDomain(), e);
}
}
}
for(String domain : domains){
if(!authorizedDomains.contains(domain)){
LOG.error("Domain " + domain + " is not authorized. Please, authorize it first.");
}else {
LOG.error("Domain " + domain + " is not verified. Please, check warnings.");
}
}
error = error || !writeAuthorizationList(authorizationList);
if (domains.size() > 0) {
JsonElement failedDomainsJsonElement = getGson().toJsonTree(domains,
new TypeToken<HashSet<String>>() {}.getType());
result.add("failed_domains", failedDomainsJsonElement);
error=true;
}
}
开发者ID:porunov,项目名称:acme_client,代码行数:44,代码来源:DownloadChallengesCommand.java
示例16: orderCertificate
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Runs the complete process of ordering a certificate.
*
* @param domain
* Name of the domain to order a certificate for
* @param validator
* {@link Validator} that finds and prepares a {@link Challenge} for domain
* validation
*/
private void orderCertificate(String domain, Validator validator) throws Exception {
KeyPair keyPair = createKeyPair();
Session session = new Session(pebbleURI(), keyPair);
Account account = new AccountBuilder()
.agreeToTermsOfService()
.create(session);
KeyPair domainKeyPair = createKeyPair();
Instant notBefore = Instant.now().truncatedTo(ChronoUnit.MILLIS);
Instant notAfter = notBefore.plus(Duration.ofDays(20L));
Order order = account.newOrder()
.domain(domain)
.notBefore(notBefore)
.notAfter(notAfter)
.create();
assertThat(order.getNotBefore(), is(notBefore));
assertThat(order.getNotAfter(), is(notAfter));
assertThat(order.getStatus(), is(Status.PENDING));
for (Authorization auth : order.getAuthorizations()) {
assertThat(auth.getDomain(), is(domain));
assertThat(auth.getStatus(), is(Status.PENDING));
Challenge challenge = validator.prepare(auth);
challenge.trigger();
await()
.pollInterval(1, SECONDS)
.timeout(30, SECONDS)
.conditionEvaluationListener(cond -> updateAuth(auth))
.until(auth::getStatus, not(isOneOf(Status.PENDING, Status.PROCESSING)));
if (auth.getStatus() != Status.VALID) {
fail("Authorization failed");
}
}
CSRBuilder csr = new CSRBuilder();
csr.addDomain(domain);
csr.sign(domainKeyPair);
byte[] encodedCsr = csr.getEncoded();
order.execute(encodedCsr);
await()
.pollInterval(1, SECONDS)
.timeout(30, SECONDS)
.conditionEvaluationListener(cond -> updateOrder(order))
.until(order::getStatus, not(isOneOf(Status.PENDING, Status.PROCESSING)));
Certificate certificate = order.getCertificate();
X509Certificate cert = certificate.getCertificate();
assertThat(cert, not(nullValue()));
assertThat(cert.getNotAfter(), not(nullValue()));
assertThat(cert.getNotBefore(), not(nullValue()));
assertThat(cert.getSubjectX500Principal().getName(), containsString("CN=" + domain));
}
开发者ID:shred,项目名称:acme4j,代码行数:71,代码来源:OrderIT.java
示例17: testDnsValidation
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Test if a wildcard certificate can be ordered via dns-01 challenge.
*/
@Test
public void testDnsValidation() throws Exception {
BammBammClient client = getBammBammClient();
KeyPair keyPair = createKeyPair();
Session session = new Session(pebbleURI(), keyPair);
Account account = new AccountBuilder()
.agreeToTermsOfService()
.create(session);
KeyPair domainKeyPair = createKeyPair();
Instant notBefore = Instant.now().truncatedTo(ChronoUnit.MILLIS);
Instant notAfter = notBefore.plus(Duration.ofDays(20L));
Order order = account.newOrder()
.domain(TEST_WILDCARD_DOMAIN)
.domain(TEST_DOMAIN)
.notBefore(notBefore)
.notAfter(notAfter)
.create();
assertThat(order.getNotBefore(), is(notBefore));
assertThat(order.getNotAfter(), is(notAfter));
assertThat(order.getStatus(), is(Status.PENDING));
for (Authorization auth : order.getAuthorizations()) {
assertThat(auth.getDomain(), is(TEST_DOMAIN));
assertThat(auth.getStatus(), is(Status.PENDING));
Dns01Challenge challenge = auth.findChallenge(Dns01Challenge.TYPE);
assertThat(challenge, is(notNullValue()));
String challengeDomainName = "_acme-challenge." + TEST_DOMAIN;
client.dnsAddTxtRecord(challengeDomainName, challenge.getDigest());
cleanup(() -> client.dnsRemoveTxtRecord(challengeDomainName));
challenge.trigger();
await()
.pollInterval(1, SECONDS)
.timeout(30, SECONDS)
.conditionEvaluationListener(cond -> updateAuth(auth))
.until(auth::getStatus, not(isOneOf(Status.PENDING, Status.PROCESSING)));
if (auth.getStatus() != Status.VALID) {
fail("Authorization failed");
}
}
CSRBuilder csr = new CSRBuilder();
csr.addDomain(TEST_DOMAIN);
csr.addDomain(TEST_WILDCARD_DOMAIN);
csr.sign(domainKeyPair);
byte[] encodedCsr = csr.getEncoded();
order.execute(encodedCsr);
await()
.pollInterval(1, SECONDS)
.timeout(30, SECONDS)
.conditionEvaluationListener(cond -> updateOrder(order))
.until(order::getStatus, not(isOneOf(Status.PENDING, Status.PROCESSING)));
Certificate certificate = order.getCertificate();
X509Certificate cert = certificate.getCertificate();
assertThat(cert, not(nullValue()));
assertThat(cert.getNotAfter(), not(nullValue()));
assertThat(cert.getNotBefore(), not(nullValue()));
assertThat(cert.getSubjectX500Principal().getName(), containsString("CN=" + TEST_DOMAIN));
List<String> san = cert.getSubjectAlternativeNames().stream()
.filter(it -> ((Number) it.get(0)).intValue() == GeneralName.dNSName)
.map(it -> (String) it.get(1))
.collect(toList());
assertThat(san, contains(TEST_DOMAIN, TEST_WILDCARD_DOMAIN));
}
开发者ID:shred,项目名称:acme4j,代码行数:82,代码来源:OrderWildcardIT.java
示例18: testHttpValidation
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Test if a certificate can be ordered via http-01 challenge.
*/
@Test
public void testHttpValidation() throws Exception {
KeyPair keyPair = createKeyPair();
Session session = new Session(boulderURI(), keyPair);
Account account = new AccountBuilder()
.agreeToTermsOfService()
.create(session);
KeyPair domainKeyPair = createKeyPair();
Order order = account.newOrder().domain(TEST_DOMAIN).create();
for (Authorization auth : order.getAuthorizations()) {
TlsSni02Challenge challenge = auth.findChallenge(TlsSni02Challenge.TYPE);
assertThat(challenge, is(notNullValue()));
KeyPair challengeKeyPair = createKeyPair();
X509Certificate challengeCert = CertificateUtils.createTlsSni02Certificate(challengeKeyPair, challenge.getSubject(), challenge.getSanB());
client.tlsSniAddCertificate(challenge.getSubject(), challengeKeyPair.getPrivate(), challengeCert);
challenge.trigger();
await()
.pollInterval(1, SECONDS)
.timeout(30, SECONDS)
.conditionEvaluationListener(cond -> updateAuth(auth))
.until(auth::getStatus, not(isOneOf(Status.PENDING, Status.PROCESSING)));
if (auth.getStatus() != Status.VALID) {
fail("Authorization failed");
}
client.tlsSniRemoveCertificate(challenge.getSubject());
}
CSRBuilder csr = new CSRBuilder();
csr.addDomain(TEST_DOMAIN);
csr.sign(domainKeyPair);
byte[] encodedCsr = csr.getEncoded();
order.execute(encodedCsr);
await()
.pollInterval(1, SECONDS)
.timeout(30, SECONDS)
.conditionEvaluationListener(cond -> updateOrder(order))
.until(order::getStatus, not(isOneOf(Status.PENDING, Status.PROCESSING)));
Certificate certificate = order.getCertificate();
X509Certificate cert = certificate.getCertificate();
assertThat(cert, not(nullValue()));
assertThat(cert.getNotAfter(), not(nullValue()));
assertThat(cert.getNotBefore(), not(nullValue()));
assertThat(cert.getSubjectX500Principal().getName(), containsString("CN=" + TEST_DOMAIN));
}
开发者ID:shred,项目名称:acme4j,代码行数:61,代码来源:OrderTlsSniIT.java
示例19: testHttpValidation
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Test if a certificate can be ordered via http-01 challenge.
*/
@Test
public void testHttpValidation() throws Exception {
KeyPair keyPair = createKeyPair();
Session session = new Session(boulderURI(), keyPair);
Account account = new AccountBuilder()
.agreeToTermsOfService()
.create(session);
KeyPair domainKeyPair = createKeyPair();
Order order = account.newOrder().domain(TEST_DOMAIN).create();
for (Authorization auth : order.getAuthorizations()) {
Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE);
assertThat(challenge, is(notNullValue()));
client.httpAddToken(challenge.getToken(), challenge.getAuthorization());
challenge.trigger();
await()
.pollInterval(1, SECONDS)
.timeout(30, SECONDS)
.conditionEvaluationListener(cond -> updateAuth(auth))
.until(auth::getStatus, not(isOneOf(Status.PENDING, Status.PROCESSING)));
if (auth.getStatus() != Status.VALID) {
fail("Authorization failed");
}
client.httpRemoveToken(challenge.getToken());
}
CSRBuilder csr = new CSRBuilder();
csr.addDomain(TEST_DOMAIN);
csr.sign(domainKeyPair);
byte[] encodedCsr = csr.getEncoded();
order.execute(encodedCsr);
await()
.pollInterval(1, SECONDS)
.timeout(30, SECONDS)
.conditionEvaluationListener(cond -> updateOrder(order))
.until(order::getStatus, not(isOneOf(Status.PENDING, Status.PROCESSING)));
Certificate certificate = order.getCertificate();
X509Certificate cert = certificate.getCertificate();
assertThat(cert, not(nullValue()));
assertThat(cert.getNotAfter(), not(nullValue()));
assertThat(cert.getNotBefore(), not(nullValue()));
assertThat(cert.getSubjectX500Principal().getName(), containsString("CN=" + TEST_DOMAIN));
}
开发者ID:shred,项目名称:acme4j,代码行数:58,代码来源:OrderHttpIT.java
示例20: authorize
import org.shredzone.acme4j.Authorization; //导入依赖的package包/类
/**
* Authorize a domain. It will be associated with your account, so you will be able to
* retrieve a signed certificate for the domain later.
* <p>
* You need separate authorizations for subdomains (e.g. "www" subdomain). Wildcard
* certificates are not currently supported.
*
* @param reg
* {@link Registration} of your account
* @param domain
* Name of the domain to authorize
*/
private void authorize(Registration reg, String domain) throws AcmeException {
// Authorize the domain.
Authorization auth = reg.authorizeDomain(domain);
log.info("Authorization for domain " + domain);
// Find the desired challenge and prepare it.
Http01Challenge challenge = httpChallenge(auth, domain);
contentHolder.content = challenge.getAuthorization();
// If the challenge is already verified, there's no need to execute it again.
if (challenge.getStatus() == Status.VALID) {
return;
}
// Now trigger the challenge.
challenge.trigger();
// Poll for the challenge to complete.
try {
int attempts = ATTEMPTS;
while (challenge.getStatus() != Status.VALID && attempts-- > 0) {
// Did the authorization fail?
if (challenge.getStatus() == Status.INVALID) {
throw new AcmeException("Challenge failed... Giving up.");
}
// Wait for a few seconds
Thread.sleep(WAIT_MILLIS);
// Then update the status
challenge.update();
}
} catch (InterruptedException ex) {
log.error("interrupted", ex);
Thread.currentThread().interrupt();
}
// All reattempts are used up and there is still no valid authorization?
if (challenge.getStatus() != Status.VALID) {
throw new AcmeException("Failed to pass the challenge for domain " + domain + ", ... Giving up.");
}
}
开发者ID:blynkkk,项目名称:blynk-server,代码行数:55,代码来源:AcmeClient.java
注:本文中的org.shredzone.acme4j.Authorization类示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论