Skip to content

Accept profile URLs and resolve to Steam64#65

Open
emihai-dev wants to merge 2 commits intocsfloat:masterfrom
emihai-dev:master
Open

Accept profile URLs and resolve to Steam64#65
emihai-dev wants to merge 2 commits intocsfloat:masterfrom
emihai-dev:master

Conversation

@emihai-dev
Copy link
Copy Markdown

@emihai-dev emihai-dev commented Mar 24, 2026

  • What changed

The app used to expect a SteamID64 (plain number). This adds support for pasting a Steam profile link too /profiles/7656119… and /id/yourvanity and turns whatever they pasted into a SteamID64 before the rest of the flow runs.

  • How vanity names become an ID

Custom URLs don’t include the 64‑bit ID in the path, so we have to resolve the name. The default path uses Valve’s old community profile XML (steamcommunity.com/id/{vanity}?xml=1) and reads from the response.

  • Optional Web API

The ?xml=1 request is basically scraping the community site; Steam can rate-limit or block heavy traffic. If you configure a Steam Web API key, you can use ResolveVanityURL instead of the XML scrape for /id/

@emihai-dev
Copy link
Copy Markdown
Author

@hayesZach I've addressed the changes. Let me know if you want me to squash the 2 commits into a single one. For now, I've added a separate commit for visibility.

Comment on lines +64 to +69
if u.Scheme == "" {
u, err = url.Parse("https://" + raw)
if err != nil {
return nil, errors.New(errors.BadRequest, "invalid vanityUrl", err)
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why reparse again if the first one succeeded?

Comment on lines +71 to +73
if !strings.EqualFold(u.Scheme, "http") && !strings.EqualFold(u.Scheme, "https") {
return nil, errors.New(errors.BadRequest, "url scheme must be http or https")
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can just omit this check since the parsing succeeded.


host := strings.ToLower(strings.TrimPrefix(u.Hostname(), "www."))
if host != "steamcommunity.com" {
return nil, errors.New(errors.BadRequest, fmt.Sprintf("expected steamcommunity.com, got %q", host))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can use errors.Newf(...)

}

// If it already looks like a SteamID64, skip the resolve endpoint.
if (/^\d{16,20}$/.test(trimmed)) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can handle extracting the steamid from the steamcommunity.com/profiles/<steamid> here.

Comment on lines +486 to +492
let msg = 'could not resolve steam id';
try {
const errorData = await res.json();
msg = `${errorData.code} - ${errorData.message}` + (errorData.details ? ` (${errorData.details})` : '');
} catch (_) {}
throw new Error(msg);
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can let the caller handle constructing the error message. That way all the error string construction logic is in one place. You can decode the json here and if !data.ok, we throw data back to the caller. Then the caller's catch block handles constructing the error message.

Comment on lines +96 to +102
func (s *Service) resolveVanity(ctx context.Context, vanity string) (*models.SteamID, error) {
key, ok := s.keys.Next()
if !ok {
return nil, errors.New(errors.BadRequest, "steam web api keys not configured")
}
return resolveVanityWebAPI(ctx, s.client, key, vanity)
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really necessary to have this a separate function. Unlikely it will ever be called by something else.

for {
old := atomic.LoadUint32(&r.idx)
i := old % uint32(n)
next := (old + 1) % uint32(n)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, we should be fine with next := old + 1. The overflow will naturally wrap around to zero. Sorry for the confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants