You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: dev-docs/README.md
+8-10Lines changed: 8 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,7 +25,7 @@ Let's get the HCB codebase set up on your computer! We have setup a easy and sim
25
25
26
26
## HCB's Structure
27
27
28
-
We've been building HCB since 2018, navigating the codebase can be difficult at times. The codebase generally follows the [Model-View-Controller](https://developer.mozilla.org/en-US/docs/Glossary/MVC) design pattern, which Ruby on Rails is built around. If you need help, reach out to us in [#hcb-dev](https://hackclub.slack.com/archives/C068U0JMV19). ["Getting Started with Rails"](https://guides.rubyonrails.org/getting_started.html) is a comprehensive guide for first-time Rails developers.
28
+
We've been building HCB since 2018, so navigating the codebase can be difficult at times. The codebase generally follows the [Model-View-Controller](https://developer.mozilla.org/en-US/docs/Glossary/MVC) design pattern, which Ruby on Rails is built around. If you need help, reach out to us in [#hcb-dev](https://hackclub.slack.com/archives/C068U0JMV19). ["Getting Started with Rails"](https://guides.rubyonrails.org/getting_started.html) is a comprehensive guide for first-time Rails developers.
29
29
30
30
### Organizations
31
31
@@ -39,8 +39,6 @@ We use [Stripe](https://stripe.com/) to enable invoice sending ([Stripe Invoicin
39
39
40
40
Column is used to send checks, accept check deposits, send ACH transfers, generate an organization's account / routing number and create book transfers (these represent internal transfers). Refer to [Column's documentation](https://column.com/docs) for more information.
41
41
42
-
PayPal transfers are sent manually by HCB's operations staff.
43
-
44
42
Disbursements are internal transfers from one organization to another. These are sometimes called “HCB transfers” in the interface.
45
43
46
44
Reimbursements are internal transfers to a "clearinghouse" organization on HCB which then sends an external transfer via ACH, check etc.
@@ -49,39 +47,39 @@ In the past, we've used [Increase](https://www.increase.com/), [Emburse](https:/
49
47
50
48
#### Receipts
51
49
52
-
Card transactions as well as ACHs, reimbursements, checks, and PayPal transfers require receipts. Models that allow adding receipts include the [`Receiptable`](https://github.com/hackclub/hcb/blob/main/app/models/concerns/receiptable.rb) concern. Receipt Bin is a tool created to manage "unlinked" receipts that haven't been paired to transactions, these receipts have their `receiptable_id` set to `nil`.
50
+
Card transactions as well as ACHs, reimbursements, checks, and PayPal transfers require receipts. Models that allow adding receipts include the [`Receiptable`](https://github.com/hackclub/hcb/blob/main/app/models/concerns/receiptable.rb) concern ([what's a concern?](https://api.rubyonrails.org/classes/ActiveSupport/Concern.html)). Receipt Bin is a tool created to manage "unlinked" receipts that haven't been paired to transactions, these receipts have their `receiptable_id` set to `nil`.
53
51
54
52
#### Fees
55
53
56
54
We collect fees on all revenue collected by organizations, typically 7%. This process is handled by a set of cron jobs and we make book transfers on our Column account to represent money moving from an organization's account to our operating fund.
57
55
58
56
### Transaction Engine
59
57
60
-
The transaction engine is the core of HCB's codebase. It's role is to map transactions that happen in on our underlying bank accounts to their associated organization. Almost every action a user takes on HCB will go through the transaction engine at some point.
58
+
The transaction engine is the core of HCB's codebase. Its role is to map transactions that happen in on our underlying bank accounts to their associated organization. Almost every action a user takes on HCB will go through the transaction engine at some point.
61
59
62
60
Our transaction engine is summarised in [@sampoder](https://github.com/sampoder)'s talk at the SF Bay Area Ruby Meetup: [How we built a bank w/ Ruby on Rails](https://www.youtube.com/watch?v=CBxilReUkJ0&t=3553s).
Canonical pending transactions are transactions we expect to take place but they haven't occurred yet in our underlying bank account. For example, we create a canonical pending transaction the moment you send an ACH transfer even though the transfer only gets sent via Column once a operations staff member has approved.
64
+
`CanonicalPendingTransaction`s are transactions we expect to take place but they haven't occurred yet in our underlying bank account. For example, we create a `CanonicalPendingTransaction` the moment you send an ACH transfer even though the transfer only gets sent via Column once a operations staff member has approved.
67
65
68
-
Canonical pending transactions appear on the ledger as "PENDING:" until a canonical transaction is made.
66
+
`CanonicalPendingTransaction`s appear on the ledger as "PENDING:" until a `CanonicalTransaction` is made.
Canonical transactions represent transactions that occur on our underlying bank account / show up on our bank statement. Our accountants and auditors rely on each transaction (including internal transfers) appearing on our bank statements.
70
+
`CanonicalTransaction`s represent transactions that occur on our underlying bank account / show up on our bank statement. Our accountants and auditors rely on each transaction (including internal transfers) appearing on our bank statements.
HCB codes group together canonical transactions and canonical pending transactions into transactions we can display on the ledger. For example, a donation has a canonical transaction for both the money paid through the card and a refund for the Stripe processing fee. When we display a transactions, we display the HCB code.
82
+
HCB codes group together `CanonicalTransaction`s and `CanonicalPendingTransaction`s into transactions we can display on the ledger. For example, a donation has a `CanonicalTransaction` for both the money paid through the card and a refund for the Stripe processing fee. When we display a transactions, we display the HCB code.
Copy file name to clipboardExpand all lines: dev-docs/development.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,7 +18,7 @@ Once HCB is running locally, log in into your local instance using the email `ad
18
18
19
19
[](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=135250235&skip_quickstart=true&machine=premiumLinux&devcontainer_path=.devcontainer%2Fdevcontainer.json&geo=UsWest)
20
20
21
-
[GitHub Codespaces](https://docs.github.com/en/codespaces) allows you to run a development environment without installing anything on your computer, allows for multiple instances, creates an overall streamlined and reproducible environment, and enables anyone with browser or VS Code access to contribute.
21
+
[GitHub Codespaces](https://docs.github.com/en/codespaces) allows you to run a development environment without installing anything on your computer, allows for multiple instances, creates an overall streamlined and reproducible environment, and enables anyone with VS Code to contribute.
22
22
23
23
To get started, [whip up a codespace](https://docs.github.com/en/codespaces/getting-started/quickstart), open the command palette(<kbd>CTRL</kbd>+<kbd>SHIFT</kbd>+<kbd>P</kbd>), and search `Codespaces: Open in VS Code Desktop`. HCB does not work on the web version of Codespaces.
24
24
@@ -169,7 +169,7 @@ All PRs are deployed in a staging enviroment using Heroku. Login using the email
169
169
170
170
External contributors should provide credentials via a `.env.development` file [(view example)](/.env.development.example). Developers using the `devcontainer` setup (eg. in GitHub Codespaces), will need to rebuild the container after modifying the `.env.development` file to pull in the new variables.
171
171
172
-
HCB relies on two services for the majority of it's financial features: Stripe and Column. Follow [the Stripe testing guide](./stripe_testing.md) to setup Stripe. You can register for a Column account [here](https://dashboard.column.com/register); after their onboarding questions, select "Skip to Sandbox".
172
+
HCB relies on two services for the majority of its financial features: Stripe and Column. Follow [the Stripe testing guide](./stripe_testing.md) to setup Stripe. You can register for a Column account [here](https://dashboard.column.com/register); after their onboarding questions, select "Skip to Sandbox".
173
173
174
174
We also include OpenAI and Twilio keys in our `.env.development` file. Information about obtaining these keys is available in these articles on [help.openai.com](https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key) and [twilio.com](https://www.twilio.com/docs/iam/api-keys/keys-in-console).
Copy file name to clipboardExpand all lines: dev-docs/guides/authentication.md
+9-9Lines changed: 9 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,8 @@
1
1
# Authentication on HCB
2
-
HCB’s authentication system is an awkward hodgepodge of systems, built one on top of the other. I’m going to start by off by listing off the models and their purpose:
2
+
HCB’s authentication system is an awkward hodgepodge of systems, built one on top of the other. I’m going to start off by listing the models and their purposes:
3
3
4
4
*`Login`: stores information about an attempt to login, whether successful or not. It’s created when someone enters their email address and either expires or ends after they’ve provided one or two factors of authentication, which creates a `UserSession`.
5
-
*`LoginCode`: is a temporary code sent via email to users, they can use this code as authentication factor.
5
+
*`LoginCode`: a temporary code sent via email to users. They can use this code as an authentication factor.
6
6
*`LoginCodeService::Request` confusingly can also send SMS login codes, however, these don’t have an associated `LoginCode` record and are done through Twilio.
7
7
*`User::Totp`: a TOTP credential that users can use to login. One-per-user.
8
8
*`WebauthnCredential`: a WebAuthn credential that users can use to login, eg. a fingerprint or a Yubikey. Users can have multiple.
@@ -14,20 +14,20 @@ Logging in starts in the `LoginsController`, the `new` route renders the page fo
14
14
15
15
From there, it’ll set a cookie that’ll act as the “browser token”. It will be used to make sure that this `Login` record is only used in this browser.
16
16
17
-
If this computer has a `login_preference` set (using [Rails’ sessions](https://guides.rubyonrails.org/v4.1/action_controller_overview.html#session)), it will redirect you to either `totp_login_path` or `login_code_login_path`. Otherwise, it will redirect you to `choose_login_preference_login_path` or `login_code_login_path` if you don’t have TOTP / WebAuthn setup.
17
+
If the computer has a `login_preference` set (using [Rails’ sessions](https://guides.rubyonrails.org/v4.1/action_controller_overview.html#session)), it will redirect you to either `totp_login_path` or `login_code_login_path`. Otherwise, it will redirect you to `choose_login_preference_login_path` or `login_code_login_path` if you don’t have TOTP / WebAuthn setup.
18
18
19
-
`login_code_login_path` will send the user a login code via email or SMS based on their preference (stored in the `use_sms_auth` column). They can manually override this by setting `resp[:method] = :sms`. It then renders a form for them to enter this code.
19
+
`login_code_login_path` will send the user a login code via email or SMS based on their preference (stored in the `use_sms_auth` column). They can manually override this by setting `resp[:method] = :sms`. It then renders a form for them to enter this code.
20
20
21
21
`totp_login_path` renders a form for users to input their one time password.
22
22
23
-
`set_login_preference` simply gives uses a list of options to set their `login_preference` by POST-ing to `choose_login_preference`.
23
+
`set_login_preference` simply gives users a list of options to set their `login_preference` by POST-ing to `choose_login_preference`.
24
24
25
25
The forms on both `login_code_login_path` and `totp_login_path` submit to `complete_login_path`.
26
26
27
27
The complete method does two things:
28
28
29
-
1) It verifies whether what the user inputted is valid. Is it a valid login code / one time password etc.? Once verified it will mark that method as completed on the login record as follows: `@login.update(authenticated_with_webauthn: true)`. This is done so that we can keep track of unique factors used for two factor authentication.
30
-
2)It transitions the `Login` record to complete, if possible. This is done when the user has authenticated with the required amount of factors (1 or 2, depending on if 2FA is enabled). That is determined in an AASM state guard clause on the `Login` model.
29
+
1) It verifies whether what the user inputted is valid. Is it a valid login code, one time password, etc? Once verified, it will mark that method as completed on the login record as follows: `@login.update(authenticated_with_webauthn: true)`. This is done so that we can keep track of unique factors used for two factor authentication.
30
+
2)If possible, it transitions the `Login` record to complete. This is done when the user has authenticated with the required amount of factors (1 or 2, depending on if 2FA is enabled). That is determined in an AASM state guard clause on the `Login` model.
31
31
32
32
Lastly, if the login is complete, this line signs the user in:
33
33
@@ -41,10 +41,10 @@ WebAuthn credentials are done slightly differently to login codes and TOTPs. Ins
41
41
42
42
If WebAuthn is available and the security key works in the browser, we make a request to `complete_login_path` or `complete_logins_path`. The reason for `complete_logins_path` is that if this is the form where you input your email, a `Login` record won’t have been created.
43
43
44
-
We use GitHub’s `@github/webauthn-json` package and most of this logic is contained in `webauthn_auth_controller.js`.
44
+
We use GitHub’s [`@github/webauthn-json`](https://github.com/github/webauthn-json) package and most of this logic is contained in `webauthn_auth_controller.js`.
45
45
46
46
## Fingerprinting
47
47
48
-
We fingerprint every user session using `@fingerprintjs/fingerprintjs`. This is passed into the `UserSession` created inside of `complete_login_path`.
48
+
We fingerprint every user session using [`@fingerprintjs/fingerprintjs`](https://github.com/fingerprintjs/fingerprintjs). This is passed into the `UserSession` created inside of `complete_login_path`.
Copy file name to clipboardExpand all lines: dev-docs/guides/card_transactions.md
+6-6Lines changed: 6 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,23 +1,23 @@
1
1
# What happens when I swipe / tap / dip my HCB card?
2
2
3
-
Our cards are issued by Stripe so the process starts with them. They have a socket connection with Visa’s card network which receives a message when you attempt to buy something with your card, they do their preliminary checks (including the $40k daily maximum on each card configured in Stripe) and, if the authorisation passes, then pass information about the authorisation to us via a webhook. At this point, it’s up to us to approve or reject the “authorisation”. An authorisation is different from a transaction:
3
+
Our cards are issued by Stripe so the process starts with them. They have a socket connection with Visa’s card network which receives a message when you attempt to buy something with your card. They do their preliminary checks (including the $40k daily maximum on each card configured in Stripe) and, if the authorisation passes, they pass information about the authorisation to us via a webhook. At this point, it’s up to us to approve or reject the “authorisation”. An authorisation is different from a transaction:
4
4
5
5
> Card authorisation is the process in which the financial institution that issued a credit or debit card that’s been submitted for payment verifies that the card can be used for a given transaction.
6
6
7
-
Authorisations aren’t guaranteed to become transactions but they often do. When Stripe sends us this webhook it has handled by `StripeController#handle_issuing_authorization_request` which calls `StripeAuthorizationService::Webhook::HandleIssuingAuthorizationRequest`. That service checks that the card has the balance available for the authorisation (based on the card’s event / subledger balance, the cardholder’s spending controls) and that this type of purchase is allowed (card grants have category / merchant locks and all cards have a cash withdrawal lock).
7
+
Authorisations aren’t guaranteed to become transactions but they often do. When Stripe sends us this webhook it is handled by `StripeController#handle_issuing_authorization_request` which calls `StripeAuthorizationService::Webhook::HandleIssuingAuthorizationRequest`. That service checks that the card has the balance available for the authorisation (based on the card’s event / subledger balance and the cardholder’s spending controls) and that this type of purchase is allowed (card grants have category / merchant locks and all cards have a cash withdrawal lock).
8
8
9
9
We then respond to the webhook with an approved / not approved message. We are required to respond within two seconds otherwise the authorisation will be declined.
10
10
11
-
No matter whether we approve or decline the transaction, Stripe will send us another webhook which will be handled by `StripeController#handle_issuing_authorization_created` . `StripeAuthorizationService::CreateFromWebhook` is called, this service does the following:
11
+
No matter whether we approve or decline the transaction, Stripe will send us another webhook which will be handled by `StripeController#handle_issuing_authorization_created` . `StripeAuthorizationService::CreateFromWebhook` is called and this service does the following:
12
12
13
13
* Creates a `RawPendingStripeTransaction`
14
14
* Creates a `CanonicalPendingTransaction`
15
-
*Map that `CanonicalPendingTransaction` to the event based on the Stripe Card’s event
15
+
*Maps that `CanonicalPendingTransaction` to the event based on the Stripe Card’s event
16
16
* If we declined the webhook, it will then:
17
17
* Decline the `CanonicalPendingTransaction`
18
18
* Send a text message / email to the card owner
19
-
* If we approved the webhook, it will email and text the card owner to let them know.
20
-
* We’ll also email the admin notification email if it was a cash withdrawal.
19
+
* If we approved the webhook, it will email and text the card owner to let them know
20
+
* We’ll also email the admin notification email if it was a cash withdrawal
21
21
22
22
At the same time, Stripe deducts the authorisation’s amount from our Issuing balance and holds it until the authorisation is either captured, voided, or expired without capture (we’ll go through these soon!).
0 commit comments