garagescript / curriculum Goto Github PK
View Code? Open in Web Editor NEWGarageScript Curriculum
GarageScript Curriculum
This thread is to document what is needed for typescript in our curriculum, so we could make sure our typescript challenge covers what we used in the codebase.
Upload images, then right click to get url to the image!
Add test to ensure the solution returns null after calling the input function num
times to match the problem description.
While trying to figure out how to replace c0d3.com's email system, I thought it would be nice to setup our own email servers for our students to use. This quickly threw me down a rabbit hole of how email servers work.
Setting up an email server is hard. When I started on this journey I didn't know what the keywords are to search for, making it difficult to find the content you need to understand how it works. If you simply looked up how to send emails
, you will get pagefuls of tutorials telling you how to connect to gmail smtp
, SES smtp
, etc. Hard to find articles on how to setup your own server that sends emails, to run your own email delivery service.
This article is a documentation of the steps I took to run my own server that delivers my emails directly so I have a reference in case I need to set this up again in the future. Hopefully it helps someone out there.
This article should cover what is spf, dkim, and dmarc conceptually and how each of these are used as security measures to prevent spam.
This article also documents a few different tools that helped my debug and helped me make sure that my email server is configured correctly.
Below will be a list of steps that I took to set it up my own email server.
Make sure Port 25 is turned on. Sending emails requires back and forth communication between servers on port 25. Because of spam, most hosting companies block port 25. Hostwinds (referral) is an example of a hosting company that allows port 25 by default (I tested this tutorial on their $5 server - Ubuntu 18.04).
After I ssh'd into server, I made sure to enable firewall on port 25: ufw allow 25
I used an application called sendmail
to send email.
sudo apt install sendmail
With sendmail installed, I could have sent my first email! Tip: Do not send to a gmail or an email powered by google at this point. If you do this without your server configured correctly (covered in the later sections), your server's ip will be blacklisted and may take 2 weeks to remove after filling out this blacklist removal form.
Sample output of my ip adress being blocked by gmail. Notice the message Our system has detected an unusual rate of unsolicited mail originating from your IP address
...
To make sure my sendmail application can deliver emails I used ethereal.email to generate emails on the fly and sent the account an email.
sendmail -v [email protected]
Subject: sample email subject here
email body goes here.
.
Make sure you exit out of the program by putting .
on a new line an hitting enter. You should see messages output from the console. If you do not, you can find the logs in /var/log/mail.log
.
I was able to verify that the email arrived in the email inbox and here's a sample output from my console:
Now that I can send a shitty email (that will probably get my server immediately blacklisted), it is time to make it legit.
First I need a domain name. I got my domain name from godaddy. For the rest of the example I will be using my domain name m8l.me
. I want my email server to be recognizable by domain name (smtp.m8l.me
) so I added an A
record for smtp.m8l.me
to point to the ip address of our server.
(optional) - You should set your mx
record to your subdomain for sending emails: smtp.m8l.me
. When other servers (like gmail) need to deliver emails to your domain, they will look at this record to figure out where to send the email to. This tutorial does not show you how to receive emails, but setting up this record helps legitimize your domain.
Record | Host | points to |
---|---|---|
A | smtp | 104.958.243.486 |
MX | smtp | smtp.m8l.me |
Now when my server sends an email to gmail, gmail is going to do a reverse dns
lookup to get domain name from the ip address of my server (Opposite from the usual dns lookup where it gets ip address from the domain name). To set this, I went to my hosting company where I got my server and configured the reverse DNS. Here is a direct link I used to configure my hostwind server reverse DNS record. I made sure both ipv4
and ipv6
ip addresses are configured with smtp.m8l.me
.
To verify that reverse DNS is setup correctly, I ran dig -x 104.958.243.486
to see what domain name my ip address resolved to.
Now that my server is all mapped correctly to the domain, I need to make sure sendmail
on my server identifies itself correctly when communicating with other email servers. Type hostname
into the terminal on your server to see how it currently identifies itself. I want it to say smtp.m8l.me
.
Here's what I did to set the hostname
property on my server:
hostnamectl
: sudo hostnamectl set-hostname smtp.m8l.me
/etc/hostname
hostnamectl
Lastly, I deleted all the records and added smtp.m8l.me
to this file: /etc/mail/local-host-names
.
When my server sends an email to gmail servers, they will first do a reverse dns lookup from my server's ip address to get the domain name. With this domain name gmail servers will look up my domain name's spf
info to verify that my server has the permission to send email on behalf of that domain name.
To lookup a site's spf
info (like gmail servers) you can look it up by fetching all the TXT records for the domain. To do this, run nslookup -q=TXT smtp.m8l.me
in the terminal to get the TXT records for smtp.m8l.me
.
To set my spf
info, I needed to set my domain name's TXT
record:
host | TXT Value |
---|---|
smtp | v=spf1 ip4:104.958.243.486 include:smtp.m8l.me -all |
In the above record:
v=spf1
means version is spf1
spec. This specifies how to interpret the rest of the string.ip:104...
means that my email server (ip of 104...) has permission to send emails.include:smtp.m8l.me
means that smtp.m8l.me
may be sending emails on my behalf (not 100% necessary for my case, but I put this anyways).-all
means the end of the string.To verify that your TXT
records are properly set, run nslookup -q=TXT smtp.m8l.me
and look for the record that starts with v=spf1...
.
After verifying that my server has the permission to deliver email, gmail servers now needs to get my security information. It does this by looking at the dkim
info for my domain name, which should specify the encryption that the email will use and the public key. In order to set this, I first need to generate a key.
To generate a public / private key, I needed to install opendkim
and then mint the key (2 new files).
sudo apt-get install opendkim opendkim-tools
opendkim-genkey -b 1024 -s mail -d smtp.m8l.me
-b 1024
is important to make sure your dkim record is usable.-s mail
mail is going to be your Selector
(important later when configuring dkim
DNS info and opendkim encryption service).-d smtp.m8l.me
- the domain name for the key to be associated with.I will get back 2 new files.
mail.txt specifies what how to set the dkim
info for my domain name. Below is a sample output.
mail._domainkey IN TXT ("v1-DKIM1; h=sha256; k=rsa; p=M...DAQAB") ; -- DKIM key default for smtp.m8l.me
mail.private is a private key that sendmail will use to encrypt outgoing emails.
Based on the content in mail.txt
, I filled out my TXT
record on my domain name provider like this:
host | TXT Value |
---|---|
mail._domainkey.smtp | v=DKIM1; h=sha256; k=rsa; p=MIG...DAQAB |
host
, notice .smtp
at the end. This is the subdomain of my domain name.v=DKIM1;
- specifies how to read the rest of the stringh=sha256
and k=rsa;
specifies the encryption and the type of key.p=MIG...DAQAB
is your public key.mail.txt
record may have quotes. Make sure you don't have any quotes ("
) in your TXT
value!Remove mail.txt
because we don't need it anymore: rm mail.txt
After gmail servers gets my public key from your dkim
info of your domain name, they will now expect encrypted email from me. sendmail
needs opendkim
server to do all the encryption so I need to setup opendkim
server and configure sendmail to encrypt emails with opendkim
.
First I need to make sure I move my private key (mail.private
) to the correct place.
sudo mkdir /etc/opendkim
sudo mv mail.private /etc/opendkim/
Now I want to configure opendkim
service to encrypt with the correct key and specify the correct domain.
vim /etc/opendkim.conf
Domain smtp.m8l.me
KeyFile /etc/opendkim/mail.private
Selector mail
mail
is the Selector I used to generate the original key.
In the same file, I need to specify the socket to run on the correct port.
Socket inet:8891@localhost
Make sure all other instances of Socket
are commented out.
Now edit another opendkim
config file: vim /etc/default/opendkim
SOCKET="inet:8891@localhost" # listen on loopback on port 8891
Start/Restart opendkim
service: sudo systemctl restart opendkim
or sudo systemctl start opendkim
.
To make sure my server is running on the correct specified port (8891
), I ran lsof -i:8891
to check.
COMMAND | PID | USER | FD | TYPE | DEVICE | SIZE/OFF | NODE | NAME |
---|---|---|---|---|---|---|---|---|
opendkim | 1920 | opendkim | 3u | IPv4 | 81346 | 0t0 | TCP | localhost:8891 (LISTEN) |
Lastly, I needed to configure sendmail
to use this opendkim service to encrypt emails.
Append the following into /etc/mail/sendmail.mc
INPUT_MAIL_FILTER(`opendkim', `S=inet:8891@localhost')
Regenerate sendmail
config file as root:
sudo -i
m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf
Restart sendmail
sudo systemctl restart sendmail
Now I'm almost legit, there is one last step. Email servers like gmail will eventually get alot of requests that tries to pretend to be my domain. I need a DMARC
info for my domain name so that gmail knows what to do when they receive these hostile emails that tries to impersonate my domain name.
To do this, I add a TXT
record in my domain name's DNS records.
host | txt value |
---|---|
_dmarc.smtp | v=DMARC1;p=reject;pct=100;rua=[email protected] |
_dmarc.smtp
- Careful, make sure you put in the _dmarc
subdomain prefix in front of your subdomain.v=DMARC1;
- specifies how to read the rest of the stringp=reject;pct=100
- Reject 100% of all emails that are trying to impersonate my domain name.mailto:[email protected]
- Send aggregated reports of how many emails were rejected to [email protected]
Now that I have the key components of an email configured, it is time to test it.
To make sure opendkim
is configured correctly, I tailed dkim
logs:
sudo tail -f /var/log/syslog | grep -i dkim
To check if I had specified everything correctly, I searched for email deliverability test
(this is a key word) that helps me verify my records. The easiest and did not require any signups is www.mail-tester.com. I sent an email to the provided address and got a 8.9/10
on my report!
Clicking on each section would tell you how what you configured incorrectly and why.
You con now use nodemailer and configure it to use sendmail
as the transport layer. Sample code:
const transporter = nodemailer.createTransport({
sendmail: true,
newline: "unix",
path: "/usr/sbin/sendmail",
});
transporter.sendMail(
{
from: "[email protected]",
to: "[email protected]",
subject: "Message with dmarc",
text: "I hope this message gets delivered!",
},
(err, info) => {
console.log('info envelope', info.envelope);
console.log('message id', info.messageId);
console.log('error', err)
}
);
If you send with nodemailer, you should have a score of 10/10! The only thing that you can improve on at this point is to add a List-Unsubscribe header
but that is only necessary when you send out regular newsletters.
All the work I did above is so that I can send emails to common email providers like gmail, outlook, yahoo, etc. without being blocked. Summary of the steps I took:
DNS
TXT
record for spf
, dkim
, dmarc
.A
and MX
recordsServer Provider
Server
opendkim
to use generated private keysendmail
to use opendkim
serversudo apt install
that looks like this? E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
apt
process is running, perhaps an upgrade in the background. Run ps aux | grep -i apt
to see what apt
process are running.There is no test to ensure the function is called only two times, so the following code will pass tests when it probably shouldn't:
const solution = (a, fun) => {
setTimeout(() => {
solution(fun(), fun)
}, a)
}
Today I learned about template strings functions!
let person = 'Mike';
let age = 28;
function myTag(strings, personExp, ageExp) {
let str0 = strings[0]; // "That "
let str1 = strings[1]; // " is a "
let str2 = strings[2]; // "."
let ageStr;
if (ageExp > 99){
ageStr = 'centenarian';
} else {
ageStr = 'youngster';
}
// We can even return a string built using a template literal
return `${str0}${personExp}${str1}${ageStr}${str2}`;
}
let output = myTag`That ${ person } is a ${ age }.`;
console.log(output);
// That Mike is a youngster.
@chriscodes17: A student submitted an answer for 1/3.JS where if the input number was negative the answer would result in a max call stack.
so ...
is the spread operation. So if you have:
const a = [9,8,7]
then ...a
is literally, 9,8,7
(without the [
)
so then....
const a = [9,8,7]
console.log(...a) // you are calling this function with 3 arguments, 9,8,7
so...
const a= [9,8,7]
const b = [...a, {}]
What is happening here with b
is [9,8,7, {}]]
The description for this problem is:
Write a function that takes in an array of numbers and a number, and returns true if any pairs add up to the number. (The numbers in the array is unique, meaning there will be no duplicate numbers) solution([1,2,22,333,23], 25) // returns true solution([1,2,22,333,23], 24) // returns true
However, the last test case tests the input [0, 0, 0], 0
, all duplicate values.
Is the test case wrong, or is the description wrong for this problem?
Fundamentally, the way the web works currently like this:
All request / response to the World Wide Web is actually based on the ip address of your router / modem. This is not gonna work for P2P. For P2P, you need to establish a direct connection from computer to computer. We use a STUN
server to help establish a connection between 2 computers directly. Unfortunately, STUN
server can't help you establish direct connections when a computer is within an complex internal network with VPNs and Proxies (usually within corporate companies). When this happens, you can use a TURN
server. Since direct P2P cannot be established, TURN server handles media and data like a middleman between 2 computers.
Since TURN server may have to handle alot of media data, companies usually don't let you use their TURN server for free. Good news is, you can set one up yourself for free
We will be building a group video chat app.
Overview:
sendBroadcast
function that broadcasts an event to tell everyone in the channel that I have a video! Eventname: broadcastAvailable
.broadcastAvailable
event, the page checks to see if the/watch
) are gonna receive the event. If they are already watching that stream, then they're like... I can ignore this
. Otherwise, they'll send a message to the broadcaster saying... I want this
. Let's call that event getBroadcast
.getBroadcast
event, it creates a peer connection object with a stun server (provided by google woohoo!). Then when it receives an ICE Candidate
(aka information about its client data), it needs to send that to the watcher: iceOfferCandidate
.iceOfferCandidate
event, creates a peerConnection and adds the offerCandidateA student submitted a solution that skips the first element, and it had passed all the tests.
solution([1, 2, 3], 3)
returns false
because the implementation only iterator through [2, 3]
.
From: garageScript/c0d3-cli#41
The idea is to add testing to the submitting process so that once a user selects the challenge to be submitted, it will pass through the tests before getting sent to c0d3.
This will make the review process a bit easier, mentors won't have to worry if the code works or not and can focus on other aspects of the review.
Flacial's proposal:
Use husky to run yarn test
/npm test
before git commit
is run. One downside is that what if the user is submitting from a different directory?
Several tests across generalAlgorithms
, interviewPrep
, js7
and j8
are using chai:
const expect = require('chai').expect
but the dependency is not declared in package.json
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.