commit
1d903f15a7
8 changed files with 421 additions and 0 deletions
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<groupId>cc.niushuai.project</groupId> |
||||
<artifactId>steam-token</artifactId> |
||||
<version>0.0.1</version> |
||||
<description>steam令牌计算</description> |
||||
|
||||
<properties> |
||||
<java.version>1.8</java.version> |
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
||||
<maven.compiler.source>8</maven.compiler.source> |
||||
<maven.compiler.target>8</maven.compiler.target> |
||||
|
||||
<hutool.version>5.7.22</hutool.version> |
||||
<commons.cli.version>1.3</commons.cli.version> |
||||
<lombok.version>1.18.22</lombok.version> |
||||
</properties> |
||||
|
||||
<dependencies> |
||||
|
||||
<dependency> |
||||
<groupId>cn.hutool</groupId> |
||||
<artifactId>hutool-all</artifactId> |
||||
<version>${hutool.version}</version> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>commons-cli</groupId> |
||||
<artifactId>commons-cli</artifactId> |
||||
<version>${commons.cli.version}</version> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>${lombok.version}</version> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
<repositories> |
||||
<repository> |
||||
<id>aliyun</id> |
||||
<url>https://maven.aliyun.com/repository/public</url> |
||||
<releases> |
||||
<enabled>true</enabled> |
||||
</releases> |
||||
<snapshots> |
||||
<enabled>false</enabled> |
||||
</snapshots> |
||||
</repository> |
||||
</repositories> |
||||
<pluginRepositories> |
||||
<pluginRepository> |
||||
<id>aliyun-plugin</id> |
||||
<url>https://maven.aliyun.com/repository/public</url> |
||||
<releases> |
||||
<enabled>true</enabled> |
||||
</releases> |
||||
<snapshots> |
||||
<enabled>false</enabled> |
||||
</snapshots> |
||||
</pluginRepository> |
||||
</pluginRepositories> |
||||
|
||||
<build> |
||||
<finalName>steam-token-generator</finalName> |
||||
<plugins> |
||||
<plugin> |
||||
<artifactId>maven-assembly-plugin</artifactId> |
||||
<configuration> |
||||
<appendAssemblyId>false</appendAssemblyId> |
||||
<descriptorRefs> |
||||
<descriptorRef>jar-with-dependencies</descriptorRef> |
||||
</descriptorRefs> |
||||
<archive> |
||||
<manifest> |
||||
<!-- 程序入口 --> |
||||
<mainClass>cc.niushuai.project.steam.token.SteamTokenApplication</mainClass> |
||||
</manifest> |
||||
</archive> |
||||
</configuration> |
||||
<executions> |
||||
<execution> |
||||
<id>make-assembly</id> |
||||
<phase>package</phase> |
||||
<goals> |
||||
<goal>assembly</goal> |
||||
</goals> |
||||
</execution> |
||||
</executions> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
|
||||
</project> |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
package cc.niushuai.project.steam.token; |
||||
|
||||
import cc.niushuai.project.steam.token.ins.SteamTwoFactorToken; |
||||
import cc.niushuai.project.steam.token.util.GlobalUtil; |
||||
import cn.hutool.core.date.DateUtil; |
||||
|
||||
/** |
||||
* Steam 令牌计算 |
||||
* |
||||
* @author niushuai |
||||
* @date 2022/8/29 17:53 |
||||
*/ |
||||
public class SteamTokenApplication { |
||||
|
||||
public static void main(String[] args) { |
||||
|
||||
GlobalUtil.init(args); |
||||
System.out.println("初始化命令行参数成功" + args); |
||||
|
||||
String steamGuardCode = SteamTwoFactorToken.generateSteamGuardCode(GlobalUtil.getShared_secret()); |
||||
System.out.println("当前时间: " + DateUtil.now()); |
||||
System.out.println("Steam令牌: " + steamGuardCode); |
||||
} |
||||
} |
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
package cc.niushuai.project.steam.token.entity; |
||||
|
||||
import cc.niushuai.project.steam.token.enums.GuardCalcTypeEnum; |
||||
import cc.niushuai.project.steam.token.util.GlobalUtil; |
||||
import cn.hutool.core.util.StrUtil; |
||||
import lombok.Data; |
||||
|
||||
/** |
||||
* steam文件令牌信息 |
||||
* |
||||
* @author niushuai |
||||
* @date 2022/8/30 10:47 |
||||
*/ |
||||
@Data |
||||
public class SteamCommand { |
||||
|
||||
private GuardCalcTypeEnum type; |
||||
|
||||
/** |
||||
* 直接指定秘钥 |
||||
*/ |
||||
private String sharedSecret; |
||||
|
||||
/** |
||||
* 指定steam令牌文件 从文件中读取秘钥 |
||||
*/ |
||||
private String path; |
||||
|
||||
public SteamCommand verify() { |
||||
if (StrUtil.isEmpty(sharedSecret) && StrUtil.isEmpty(path)) { |
||||
System.err.println("参数缺失!"); |
||||
printUsage(); |
||||
GlobalUtil.exit(); |
||||
} |
||||
if (StrUtil.isNotEmpty(sharedSecret)) { |
||||
this.setType(GuardCalcTypeEnum.COMMAND); |
||||
} else { |
||||
this.setType(GuardCalcTypeEnum.STEAM_FILE); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public void printUsage() { |
||||
System.out.println("usage: \n\tjava -jar steam-token-generator.jar [-sharedSecret xxx] [-path xxx]"); |
||||
System.out.println("eg: \n\tjava -jar steam-token-generator.jar -sharedSecret sJH7ffdwqgluzJK0tB6L7LklYSg="); |
||||
System.out.println("\tjava -jar steam-token-generator.jar -path Steamguard-16561111382543543"); |
||||
System.out.println("tips: \n\t两个参数任选其一, 若都传递则直接使用sharedSecret"); |
||||
} |
||||
} |
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
package cc.niushuai.project.steam.token.entity; |
||||
|
||||
import cc.niushuai.project.steam.token.enums.GuardCalcTypeEnum; |
||||
import lombok.Data; |
||||
|
||||
/** |
||||
* steam文件令牌信息 |
||||
* |
||||
* @author niushuai |
||||
* @date 2022/8/30 10:47 |
||||
*/ |
||||
@Data |
||||
public class SteamInfo { |
||||
|
||||
private GuardCalcTypeEnum type; |
||||
|
||||
private String shared_secret; |
||||
private String serial_number; |
||||
private String revocation_code; |
||||
private String uri; |
||||
private String server_time; |
||||
private String account_name; |
||||
private String token_gid; |
||||
private String identity_secret; |
||||
private String secret_1; |
||||
private String status; |
||||
private Integer steamguard_scheme; |
||||
private String steamid; |
||||
} |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
package cc.niushuai.project.steam.token.enums; |
||||
|
||||
/** |
||||
* 令牌计算类型 |
||||
* |
||||
* @author niushuai |
||||
* @date 2022/8/30 11:05 |
||||
*/ |
||||
public enum GuardCalcTypeEnum { |
||||
|
||||
/** |
||||
* 命令行参数 |
||||
*/ |
||||
COMMAND, |
||||
|
||||
/** |
||||
* 读取文件 |
||||
*/ |
||||
STEAM_FILE; |
||||
} |
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
package cc.niushuai.project.steam.token.ins; |
||||
|
||||
import cn.hutool.core.codec.Base64; |
||||
import cn.hutool.core.util.StrUtil; |
||||
|
||||
import javax.crypto.Mac; |
||||
import javax.crypto.spec.SecretKeySpec; |
||||
|
||||
/** |
||||
* SteamToken计算 |
||||
* |
||||
* @author niushuai |
||||
* @date 2022/8/29 17:55 |
||||
*/ |
||||
public class SteamTwoFactorToken { |
||||
|
||||
private static final byte[] s_rgchSteamguardCodeChars = {50, 51, 52, 53, 54, 55, 56, 57, 66, 67, 68, 70, 71, 72, 74, 75, 77, 78, 80, 81, 82, 84, 86, 87, 88, 89}; |
||||
private byte[] mSecret; |
||||
|
||||
public SteamTwoFactorToken(String sharedSecret) { |
||||
if (StrUtil.isNotEmpty(sharedSecret)) { |
||||
this.mSecret = Base64.decode(sharedSecret.getBytes()); |
||||
} else { |
||||
throw new RuntimeException("未知参数 shared_secret"); |
||||
} |
||||
} |
||||
|
||||
public static String generateSteamGuardCode(String sharedSecret) { |
||||
return new SteamTwoFactorToken(sharedSecret).generateSteamGuardCode(); |
||||
} |
||||
|
||||
public final String generateSteamGuardCode() { |
||||
return generateSteamGuardCodeForTime(currentTime()); |
||||
} |
||||
|
||||
private final String generateSteamGuardCodeForTime(long calcTime) { |
||||
if (this.mSecret == null) { |
||||
return ""; |
||||
} |
||||
byte[] bArr = new byte[8]; |
||||
long j2 = calcTime / 30; |
||||
int i = 8; |
||||
while (true) { |
||||
int i2 = i - 1; |
||||
if (i <= 0) { |
||||
break; |
||||
} |
||||
bArr[i2] = (byte) ((int) j2); |
||||
j2 >>>= 8; |
||||
i = i2; |
||||
} |
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(this.mSecret, "HmacSHA1"); |
||||
try { |
||||
Mac instance = Mac.getInstance("HmacSHA1"); |
||||
instance.init(secretKeySpec); |
||||
byte[] doFinal = instance.doFinal(bArr); |
||||
int i3 = doFinal[19] & 15; |
||||
int i4 = (doFinal[i3 + 3] & 255) | ((doFinal[i3 + 2] & 255) << 8) | ((doFinal[i3] & Byte.MAX_VALUE) << 24) | ((doFinal[i3 + 1] & 255) << 16); |
||||
byte[] bArr2 = new byte[5]; |
||||
for (int i5 = 0; i5 < 5; i5++) { |
||||
byte[] bArr3 = s_rgchSteamguardCodeChars; |
||||
bArr2[i5] = bArr3[i4 % bArr3.length]; |
||||
i4 /= bArr3.length; |
||||
} |
||||
return new String(bArr2); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 系统时间 不带毫秒 |
||||
* |
||||
* @author niushuai |
||||
* @date: 2022/8/30 10:28 |
||||
* @return: {@link long} 秒级时间戳 |
||||
*/ |
||||
public final long currentTime() { |
||||
return System.currentTimeMillis() / 1000; |
||||
} |
||||
} |
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
package cc.niushuai.project.steam.token.util; |
||||
|
||||
import cn.hutool.core.util.ReflectUtil; |
||||
import cn.hutool.json.JSONUtil; |
||||
import org.apache.commons.cli.*; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* 处理命令行参数 |
||||
* |
||||
* @author niushuai |
||||
* @date: 2022/8/30 10:42 |
||||
*/ |
||||
public class CommandParseUtil { |
||||
|
||||
public static <T> T parse(String[] args, Class<T> clazz) { |
||||
CommandLineParser parser = new DefaultParser(); |
||||
//获取字段
|
||||
Field[] fields = ReflectUtil.getFields(clazz); |
||||
//使用字段创建options,options是parse需要的参数
|
||||
Options options = new Options(); |
||||
for (Field field : fields) { |
||||
String name = field.getName(); |
||||
Option option = Option.builder(name).argName(name) |
||||
.desc(name) |
||||
.hasArg(true) |
||||
.type(field.getType()) |
||||
.build(); |
||||
options.addOption(option); |
||||
} |
||||
try { |
||||
CommandLine cl = parser.parse(options, args); |
||||
Map<String, String> map = new HashMap<>(); |
||||
for (Field argsField : fields) { |
||||
String name = argsField.getName(); |
||||
map.put(name, cl.getOptionValue(name)); |
||||
} |
||||
|
||||
return (T) JSONUtil.toBean(JSONUtil.toJsonStr(map), clazz); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
package cc.niushuai.project.steam.token.util; |
||||
|
||||
import cc.niushuai.project.steam.token.entity.SteamCommand; |
||||
import cc.niushuai.project.steam.token.entity.SteamInfo; |
||||
import cc.niushuai.project.steam.token.enums.GuardCalcTypeEnum; |
||||
import cn.hutool.core.io.FileUtil; |
||||
import cn.hutool.core.io.IORuntimeException; |
||||
import cn.hutool.core.util.StrUtil; |
||||
import cn.hutool.json.JSONUtil; |
||||
|
||||
import java.util.stream.Collectors; |
||||
|
||||
/** |
||||
* 初始化工具类 |
||||
* |
||||
* @author niushuai |
||||
* @date 2022/8/30 10:33 |
||||
*/ |
||||
public class GlobalUtil { |
||||
|
||||
private static String shared_secret = ""; |
||||
|
||||
/** |
||||
* 处理命令行参数 |
||||
* |
||||
* @param args 命令行参数 |
||||
* @author niushuai |
||||
* @date: 2022/8/30 10:52 |
||||
*/ |
||||
public static void init(String[] args) { |
||||
|
||||
SteamCommand command = CommandParseUtil.parse(args, SteamCommand.class).verify(); |
||||
System.out.println("秘钥解析类型: " + command.getType()); |
||||
|
||||
if (GuardCalcTypeEnum.COMMAND.equals(command.getType())) { |
||||
shared_secret = command.getSharedSecret(); |
||||
} else { |
||||
// 需要先读文件 再取值
|
||||
|
||||
try { |
||||
String steamGuardInfoJson = FileUtil.readLines(command.getPath(), "UTF-8").stream().collect(Collectors.joining()); |
||||
|
||||
// 文件内容转bean
|
||||
SteamInfo steamInfo = JSONUtil.toBean(steamGuardInfoJson, SteamInfo.class); |
||||
System.out.println("Steam ID: " + steamInfo.getSteamid()); |
||||
System.out.println("Steam 账户: " + steamInfo.getAccount_name()); |
||||
shared_secret = steamInfo.getShared_secret(); |
||||
} catch (IORuntimeException e) { |
||||
System.err.println("Steam令牌文件未找到: " + command.getPath() + ", 请确认路径是否正确!"); |
||||
} |
||||
} |
||||
|
||||
if (StrUtil.isEmpty(shared_secret)) { |
||||
String msg = GuardCalcTypeEnum.COMMAND.equals(command.getType()) ? "命令行shared_secret参数" : "Steam令牌文件路径"; |
||||
System.err.println("未找到相关秘钥[shared_secret], 请确认" + msg + "是否正确"); |
||||
exit(); |
||||
} |
||||
|
||||
System.out.println("shared_secret init success: " + shared_secret); |
||||
} |
||||
|
||||
public static String getShared_secret() { |
||||
return shared_secret; |
||||
} |
||||
|
||||
public static void exit() { |
||||
System.exit(0); |
||||
} |
||||
} |
Loading…
Reference in new issue