Online OJ submitter

Recently I began training for coding competitions. This requires doing a lot of problems on online judges (OJs) and submitting them.

Example of an OJ, Codeforces

Submitting your code is generally not a hard process. You log in, copy your code, paste it into the submission box, and hit “Submit”.

Example of submitting your code on Codeforces

However, since I am bored a programmer who likes to make things better and simpler, I decided to make an automatic submitter that submits to online judges, with one command.

You can find the source code here: https://github.com/david-why/submit

Usage example

$ cat test.cpp
#include <iostream>
using namespace std;
int main()
{
    int a, b, c;
    string s;
    cin >> a >> b >> c >> s;
    cout << a + b + c << " " << s << endl;
    return 0;
}
$ submit test.cpp https://atcoder.jp/contests/practice/tasks/practice_1
Trying vjudge
Trying usaco
Trying codeforces
Trying atcoder
Logging in with atcoder
Username: myjudge1
Password: <password>
Save username & password (Y/n)? y
Submitting
Status:                Status.ACCEPTED
Score:                 100 / 100
Time used:             8 ms
Memory used:           3616 KB
Incorrect question(s): 0
Additional data:       {'00_rnd_01.txt': <Status.ACCEPTED: 0>, '00_rnd_02.txt': <Status.ACCEPTED: 0>, '00_rnd_03.txt': <Status.ACCEPTED: 0>, '00_rnd_04.txt': <Status.ACCEPTED: 0>, '00_rnd_05.txt': <Status.ACCEPTED: 0>, '00_sample_1.txt': <Status.ACCEPTED: 0>, '00_sample_2.txt': <Status.ACCEPTED: 0>}
Message:               Accepted

This example submits the C++ code to this practice question on AtCoder. The code is Accepted (i.e., passed all test cases).

Design

I wanted this submitter to:

  1. Submit to an OJ with a single command, e.g. python3 submit.py code.cpp {url}, where url is the URL of the problem on the OJ (e.g. https://codeforces.com/contest/1/problem/A)
  2. Wait for and display the submission results
  3. Support multiple OJs (Codeforces, AtCoder, Luogu, USACO Training, etc.)
  4. Allow easy addition of other OJs that I find later into the program

The Submitter class

First, I made an interface-ish abstract class to define the generic API each submitter will implement. This includes parsing a URL to a problem ID, unparsing a problem ID to a URL, logging in, testing whether the submitter is logged in, submitting a file, and waiting for a submission to finish grading.

IMO, abstract base classes (ABCs) are very useful in Python. They allow you to define an interface and disallow the class to be instantiated without implementing all the abstractmethods.

Codeforces submitter

Before I started diving into the code, I realized one thing: I don’t know how the code is submitted! There is no documented API for any of the OJs, so I had to find out on my own.

Fortunately, I have a friend on my side: Chrome Developer Tools! (Not a sponsor)

Using network capturing, I quickly found out how the Codeforces submission works:

A POST request to https://codeforces.com/contest/1/submit. OK, not as hard as I expected.

But how can I get all the other weird parameters, like ftaa and bfaa?

Looking at the source code, this value is not set in the form initially but was added in later with Javascript.

OK… But is this always the case? I decided to try logging in from Python and see if the ftaa and bfaa are still just written on the page or not.

Turns out the answer is even more than no, because even logging in requires a ftaa and bfaa

From as far as I can see, the ftaa is just a random number generated by randomToken.

What about bfaa?

OK… So it’s the hash of something. What is that something? I have no idea.

But sometimes that bfaa and ftaa is set to “n/a”? Will that value work?

Oh wait, I forgot about the csrf_token! But that’s easy; it’s just hard-coded on the page.

Umm… It worked!

That just made my life a billion times easier. (I find it ironic that a value of "n/a" is allowed… That literally defies the point of having this parameter in the first place.)

With that new discovery, I quickly made the Codeforces submitter. (CodeforcesSubmitter in the code)

Other submitters

The AtCoder submitter was easy. I only needed to find a csrf_token from the page. (AtCoderSubmitter in the code)

VJudge is an interesting OJ. It doesn’t process code on its own; instead, it sends the code to various other OJs to parse and grade, then returns the data to the user. I initially tried supporting submitting directly to VJudge, but I ran into a problem: the language IDs for different OJs are different. For example, on Codeforces, the language ID for c++ is 54, while on AtCoder it is 4003, and both of these OJs are supported by VJudge. So I decided to use a different method: find the origin OJ for the problem on VJudge, and submit the code to that OJ. However, this only works for the OJs that I support (Codeforces, AtCoder, etc.). For now, I’ll leave it like that. (VJudgeSubmitter in the code)

USACO Training is also weird. It didn’t use cookies for authentication. It used a string in the query parameters, as seen in this example: https://train.usaco.org/usacogate?a=jWMRYVBaaZd. So I had to store that “a” string somewhere. I decided that the string can be stored in a cookie since the cookies aren’t read anyhow. The parsing of the returned data nearly killed me, but I did it. (USACOTrainingSubmitter in the code)

Conclusion

Thank you for reading all of this article. Building this submitter project, I learned more about how to find the “hidden” APIs of a website, and I learned that security measures without actually enforcing them are literally nothing. This submitter helped me a lot when I am doing problems; I hope it helps you as well!

Leave a Comment