commit
1d903f15a7
8 changed files with 421 additions and 0 deletions
@ -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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
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