|
1 | | -const passport = require('passport'); |
2 | | -const ORCIDStrategy = require('passport-orcid').Strategy; |
3 | | - |
4 | | -passport.use(new ORCIDStrategy({ |
5 | | - clientID: process.env.ORCID_CLIENT_ID, |
6 | | - clientSecret: process.env.ORCID_CLIENT_SECRET, |
7 | | - callbackURL: 'https://yourapp.example.com/auth/orcid/callback' |
8 | | -}, (accessToken, refreshToken, profile, done) => { |
9 | | - // profile.id is the ORCID iD |
10 | | - done(null, { orcid_id: profile.id }); |
11 | | -})); |
12 | | - |
13 | | -// Routes |
14 | | -app.get('/auth/orcid', passport.authenticate('orcid')); |
15 | | -app.get('/auth/orcid/callback', |
16 | | - passport.authenticate('orcid', { session: true }), |
17 | | - (req, res) => { |
18 | | - // Session now contains req.user.orcid_id |
19 | | - res.redirect('/pledge'); |
| 1 | +import { Client, GatewayIntentBits, TextChannel, ThreadChannel, ChannelType, EmbedBuilder } from 'discord.js'; |
| 2 | +import { BadgeClient } from 'kypria-badge-sdk'; |
| 3 | +import { promises as fs } from 'fs'; |
| 4 | +import path from 'path'; |
| 5 | +import yaml from 'js-yaml'; |
| 6 | +import { dropBadge } from './utils/dropBadge'; |
| 7 | + |
| 8 | +type BadgeConfig = { |
| 9 | + drop_channels: string[]; |
| 10 | +}; |
| 11 | + |
| 12 | +type Config = Record<string, BadgeConfig>; |
| 13 | + |
| 14 | +type SponsorPingPayload = { |
| 15 | + sponsorId: string; |
| 16 | + badgeName: string; |
| 17 | +}; |
| 18 | + |
| 19 | +type Relic = SponsorPingPayload & { |
| 20 | + timestamp: string; |
| 21 | + threadId: string; |
| 22 | +}; |
| 23 | + |
| 24 | +(async () => { |
| 25 | + // 1. Load & validate badge‐locations.yml |
| 26 | + const cfgPath = path.resolve(__dirname, '../config/badge-locations.yml'); |
| 27 | + let config: Config; |
| 28 | + try { |
| 29 | + const raw = await fs.readFile(cfgPath, 'utf8'); |
| 30 | + config = (yaml.load(raw) as Config) ?? {}; |
| 31 | + } catch (err) { |
| 32 | + console.error('❌ Failed to load badge-locations.yml:', err); |
| 33 | + process.exit(1); |
20 | 34 | } |
21 | | -); |
22 | | - |
23 | | - |
24 | | -## Git Credential Manager |
25 | | - |
26 | | -[![Build Status][build-status-badge]][workflow-status] |
27 | | - |
28 | | ---- |
29 | | - |
30 | | -[Git Credential Manager][gcm] (GCM) is a secure |
31 | | -[Git credential helper][git-credential-helper] built on [.NET][dotnet] that runs |
32 | | -on Windows, macOS, and Linux. It aims to provide a consistent and secure |
33 | | -authentication experience, including multi-factor auth, to every major source |
34 | | -control hosting service and platform. |
35 | | - |
36 | | -GCM supports (in alphabetical order) [Azure DevOps][azure-devops], Azure DevOps |
37 | | -Server (formerly Team Foundation Server), Bitbucket, GitHub, and GitLab. |
38 | | -Compare to Git's [built-in credential helpers][git-tools-credential-storage] |
39 | | -(Windows: wincred, macOS: osxkeychain, Linux: gnome-keyring/libsecret), which |
40 | | -provide single-factor authentication support for username/password only. |
41 | | - |
42 | | -GCM replaces both the .NET Framework-based |
43 | | -[Git Credential Manager for Windows][gcm-for-windows] and the Java-based |
44 | | -[Git Credential Manager for Mac and Linux][gcm-for-mac-and-linux]. |
45 | | - |
46 | | -## Install |
47 | | - |
48 | | -See the [installation instructions][install] for the current version of GCM for |
49 | | -install options for your operating system. |
50 | | - |
51 | | -## Current status |
52 | | - |
53 | | -Git Credential Manager is currently available for Windows, macOS, and Linux\*. |
54 | | -GCM only works with HTTP(S) remotes; you can still use Git with SSH: |
55 | | - |
56 | | -- [Azure DevOps SSH][azure-devops-ssh] |
57 | | -- [GitHub SSH][github-ssh] |
58 | | -- [Bitbucket SSH][bitbucket-ssh] |
59 | | - |
60 | | -Feature|Windows|macOS|Linux\* |
61 | | --|:-:|:-:|:-: |
62 | | -Installer/uninstaller|✓|✓|✓ |
63 | | -Secure platform credential storage [(see more)][gcm-credstores]|✓|✓|✓ |
64 | | -Multi-factor authentication support for Azure DevOps|✓|✓|✓ |
65 | | -Two-factor authentication support for GitHub|✓|✓|✓ |
66 | | -Two-factor authentication support for Bitbucket|✓|✓|✓ |
67 | | -Two-factor authentication support for GitLab|✓|✓|✓ |
68 | | -Windows Integrated Authentication (NTLM/Kerberos) support|✓|_N/A_|_N/A_ |
69 | | -Basic HTTP authentication support|✓|✓|✓ |
70 | | -Proxy support|✓|✓|✓ |
71 | | -`amd64` support|✓|✓|✓ |
72 | | -`x86` support|✓|_N/A_|✗ |
73 | | -`arm64` support|best effort|✓|✓ |
74 | | -`armhf` support|_N/A_|_N/A_|✓ |
75 | | - |
76 | | -(\*) GCM guarantees support only for [the Linux distributions that are officially |
77 | | -supported by dotnet][dotnet-distributions]. |
78 | | - |
79 | | -## Supported Git versions |
80 | | - |
81 | | -Git Credential Manager tries to be compatible with the broadest set of Git |
82 | | -versions (within reason). However there are some know problematic releases of |
83 | | -Git that are not compatible. |
84 | | - |
85 | | -- Git 1.x |
86 | | - |
87 | | - The initial major version of Git is not supported or tested with GCM. |
88 | | - |
89 | | -- Git 2.26.2 |
90 | | - |
91 | | - This version of Git introduced a breaking change with parsing credential |
92 | | - configuration that GCM relies on. This issue was fixed in commit |
93 | | - [`12294990`][gcm-commit-12294990] of the Git project, and released in Git |
94 | | - 2.27.0. |
95 | | - |
96 | | -## How to use |
97 | | - |
98 | | -Once it's installed and configured, Git Credential Manager is called implicitly |
99 | | -by Git. You don't have to do anything special, and GCM isn't intended to be |
100 | | -called directly by the user. For example, when pushing (`git push`) to |
101 | | -[Azure DevOps][azure-devops], [Bitbucket][bitbucket], or [GitHub][github], a |
102 | | -window will automatically open and walk you through the sign-in process. (This |
103 | | -process will look slightly different for each Git host, and even in some cases, |
104 | | -whether you've connected to an on-premises or cloud-hosted Git host.) Later Git |
105 | | -commands in the same repository will re-use existing credentials or tokens that |
106 | | -GCM has stored for as long as they're valid. |
107 | | - |
108 | | -Read full command line usage [here][gcm-usage]. |
109 | | - |
110 | | -### Configuring a proxy |
111 | | - |
112 | | -See detailed information [here][gcm-http-proxy]. |
113 | | - |
114 | | -## Additional Resources |
115 | | - |
116 | | -See the [documentation index][docs-index] for links to additional resources. |
117 | | - |
118 | | -## Experimental Features |
119 | | - |
120 | | -- [Windows broker (experimental)][gcm-windows-broker] |
121 | | - |
122 | | -## Future features |
123 | | - |
124 | | -Curious about what's coming next in the GCM project? Take a look at the [project |
125 | | -roadmap][roadmap]! You can find more details about the construction of the |
126 | | -roadmap and how to interpret it [here][roadmap-announcement]. |
127 | | - |
128 | | -## Contributing |
129 | | - |
130 | | -This project welcomes contributions and suggestions. |
131 | | -See the [contributing guide][gcm-contributing] to get started. |
132 | | - |
133 | | -This project follows [GitHub's Open Source Code of Conduct][gcm-coc]. |
134 | | - |
135 | | -## License |
136 | | - |
137 | | -We're [MIT][gcm-license] licensed. |
138 | | -When using GitHub logos, please be sure to follow the |
139 | | -[GitHub logo guidelines][github-logos]. |
140 | 35 |
|
141 | | -[azure-devops]: https://azure.microsoft.com/en-us/products/devops |
142 | | -[azure-devops-ssh]: https://docs.microsoft.com/en-us/azure/devops/repos/git/use-ssh-keys-to-authenticate?view=azure-devops |
143 | | -[bitbucket]: https://bitbucket.org |
144 | | -[bitbucket-ssh]: https://confluence.atlassian.com/bitbucket/ssh-keys-935365775.html |
145 | | -[build-status-badge]: https://github.com/git-ecosystem/git-credential-manager/actions/workflows/continuous-integration.yml/badge.svg |
146 | | -[docs-index]: https://github.com/git-ecosystem/git-credential-manager/blob/release/docs/README.md |
147 | | -[dotnet]: https://dotnet.microsoft.com |
148 | | -[dotnet-distributions]: https://learn.microsoft.com/en-us/dotnet/core/install/linux |
149 | | -[git-credential-helper]: https://git-scm.com/docs/gitcredentials |
150 | | -[gcm]: https://github.com/git-ecosystem/git-credential-manager |
151 | | -[gcm-coc]: CODE_OF_CONDUCT.md |
152 | | -[gcm-commit-12294990]: https://github.com/git/git/commit/12294990c90e043862be9eb7eb22c3784b526340 |
153 | | -[gcm-contributing]: CONTRIBUTING.md |
154 | | -[gcm-credstores]: https://github.com/git-ecosystem/git-credential-manager/blob/release/docs/credstores.md |
155 | | -[gcm-for-mac-and-linux]: https://github.com/microsoft/Git-Credential-Manager-for-Mac-and-Linux |
156 | | -[gcm-for-windows]: https://github.com/microsoft/Git-Credential-Manager-for-Windows |
157 | | -[gcm-http-proxy]: https://github.com/git-ecosystem/git-credential-manager/blob/release/docs/netconfig.md#http-proxy |
158 | | -[gcm-license]: LICENSE |
159 | | -[gcm-usage]: https://github.com/git-ecosystem/git-credential-manager/blob/release/docs/usage.md |
160 | | -[gcm-windows-broker]: https://github.com/git-ecosystem/git-credential-manager/blob/release/docs/windows-broker.md |
161 | | -[git-tools-credential-storage]: https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage |
162 | | -[github]: https://github.com |
163 | | -[github-ssh]: https://help.github.com/en/articles/connecting-to-github-with-ssh |
164 | | -[github-logos]: https://github.com/logos |
165 | | -[install]: https://github.com/git-ecosystem/git-credential-manager/blob/release/docs/install.md |
166 | | -[ms-package-repos]: https://packages.microsoft.com/repos/ |
167 | | -[roadmap]: https://github.com/git-ecosystem/git-credential-manager/milestones?direction=desc&sort=due_date&state=open |
168 | | -[roadmap-announcement]: https://github.com/git-ecosystem/git-credential-manager/discussions/1203 |
169 | | -[workflow-status]: https://github.com/git-ecosystem/git-credential-manager/actions/workflows/continuous-integration.yml |
| 36 | + // 2. Initialize clients |
| 37 | + const badgeClient = new BadgeClient({ apiToken: process.env.BADGE_API_TOKEN! }); |
| 38 | + const discord = new Client({ intents: [GatewayIntentBits.Guilds] }); |
| 39 | + |
| 40 | + discord.once('ready', () => { |
| 41 | + console.log(`✅ Discord bot ready as ${discord.user?.tag}`); |
| 42 | + }); |
| 43 | + |
| 44 | + // 3. Handle sponsorPing |
| 45 | + badgeClient.on('sponsorPing', async ({ sponsorId, badgeName }: SponsorPingPayload) => { |
| 46 | + const channels = config[badgeName]?.drop_channels ?? []; |
| 47 | + const timestamp = new Date().toISOString(); |
| 48 | + const threadId = `thread-${timestamp.replace(/[:.]/g, '-')}`; |
| 49 | + const relic: Relic = { sponsorId, badgeName, timestamp, threadId }; |
| 50 | + |
| 51 | + // 3a. Audit-log relic |
| 52 | + const logDir = path.resolve(__dirname, '../threads'); |
| 53 | + await fs.mkdir(logDir, { recursive: true }); |
| 54 | + const outPath = path.join(logDir, `relic-drop--${badgeName}--${timestamp}.json`); |
| 55 | + await fs.writeFile(outPath, JSON.stringify(relic, null, 2)); |
| 56 | + |
| 57 | + // 3b. Broadcast badge-drop |
| 58 | + for (const chId of channels) { |
| 59 | + try { |
| 60 | + const channel = await discord.channels.fetch(chId); |
| 61 | + if ( |
| 62 | + channel && |
| 63 | + (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildPublicThread) |
| 64 | + ) { |
| 65 | + // wrap payload with embed title |
| 66 | + await dropBadge(channel as TextChannel | ThreadChannel, { |
| 67 | + ...relic, |
| 68 | + title: `🏅 ${badgeName}`, |
| 69 | + }); |
| 70 | + } else { |
| 71 | + console.warn(`⚠️ Channel ${chId} is not a text/thread channel. Skipping.`); |
| 72 | + } |
| 73 | + } catch (err) { |
| 74 | + console.error(`❌ Failed to drop badge in channel ${chId}:`, err); |
| 75 | + } |
| 76 | + } |
| 77 | + }); |
| 78 | + |
| 79 | + // 4. Connect to Discord |
| 80 | + await discord.login(process.env.DISCORD_TOKEN); |
| 81 | +})(); |
0 commit comments