12 | * Note that this is not the same base58 as used by Flickr, which you may find 13 | * referenced around the Internet. 14 | *
15 | * Satoshi explains: why base-58 instead of standard base-64 encoding? 16 | *
27 | * However, note that the encoding/decoding runs in O(n²) time, so it is 28 | * not useful for large data. 29 | *
30 | * The basic idea of the encoding is to treat the data bytes as a large number
31 | * represented using base-256 digits, convert the number to be represented using
32 | * base-58 digits, preserve the exact number of leading zeros (which are
33 | * otherwise lost during the mathematical operations on the numbers), and
34 | * finally represent the resulting base-58 digits as alphanumeric ASCII
35 | * characters.
36 | */
37 | @Component
38 | public class Base58 {
39 | public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
40 | private static final char ENCODED_ZERO = ALPHABET[0];
41 | private static final int[] INDEXES = new int[128];
42 | static {
43 | Arrays.fill(INDEXES, -1);
44 | for (int i = 0; i < ALPHABET.length; i++) {
45 | INDEXES[ALPHABET[i]] = i;
46 | }
47 | }
48 |
49 | /**
50 | * Encodes the given bytes as a base58 string (no checksum is appended).
51 | *
52 | * @param input the bytes to encode
53 | * @return the base58-encoded string
54 | */
55 | public static String encode(byte[] input) {
56 | if (input.length == 0) {
57 | return "";
58 | }
59 | // Count leading zeros.
60 | int zeros = 0;
61 | while (zeros < input.length && input[zeros] == 0) {
62 | ++zeros;
63 | }
64 | // Convert base-256 digits to base-58 digits (plus conversion to ASCII
65 | // characters)
66 | input = Arrays.copyOf(input, input.length); // since we modify it in-place
67 | char[] encoded = new char[input.length * 2]; // upper bound
68 | int outputStart = encoded.length;
69 | for (int inputStart = zeros; inputStart < input.length;) {
70 | encoded[--outputStart] = ALPHABET[divmod(input, inputStart, 256, 58)];
71 | if (input[inputStart] == 0) {
72 | ++inputStart; // optimization - skip leading zeros
73 | }
74 | }
75 | // Preserve exactly as many leading encoded zeros in output as there were
76 | // leading zeros in input.
77 | while (outputStart < encoded.length && encoded[outputStart] == ENCODED_ZERO) {
78 | ++outputStart;
79 | }
80 | while (--zeros >= 0) {
81 | encoded[--outputStart] = ENCODED_ZERO;
82 | }
83 | // Return encoded string (including encoded leading zeros).
84 | return new String(encoded, outputStart, encoded.length - outputStart);
85 | }
86 |
87 | /**
88 | * Decodes the given base58 string into the original data bytes.
89 | *
90 | * @param input the base58-encoded string to decode
91 | * @return the decoded data bytes
92 | */
93 | public static byte[] decode(String input) {
94 | if (input.length() == 0) {
95 | return new byte[0];
96 | }
97 | // Convert the base58-encoded ASCII chars to a base58 byte sequence (base58
98 | // digits).
99 | byte[] input58 = new byte[input.length()];
100 | for (int i = 0; i < input.length(); ++i) {
101 | char c = input.charAt(i);
102 | int digit = c < 128 ? INDEXES[c] : -1;
103 | if (digit < 0) {
104 | throw new IllegalStateException("InvalidCharacter in base 58");
105 | }
106 | input58[i] = (byte) digit;
107 | }
108 | // Count leading zeros.
109 | int zeros = 0;
110 | while (zeros < input58.length && input58[zeros] == 0) {
111 | ++zeros;
112 | }
113 | // Convert base-58 digits to base-256 digits.
114 | byte[] decoded = new byte[input.length()];
115 | int outputStart = decoded.length;
116 | for (int inputStart = zeros; inputStart < input58.length;) {
117 | decoded[--outputStart] = divmod(input58, inputStart, 58, 256);
118 | if (input58[inputStart] == 0) {
119 | ++inputStart; // optimization - skip leading zeros
120 | }
121 | }
122 | // Ignore extra leading zeroes that were added during the calculation.
123 | while (outputStart < decoded.length && decoded[outputStart] == 0) {
124 | ++outputStart;
125 | }
126 | // Return decoded data (including original number of leading zeros).
127 | return Arrays.copyOfRange(decoded, outputStart - zeros, decoded.length);
128 | }
129 |
130 | public static BigInteger decodeToBigInteger(String input) {
131 | return new BigInteger(1, decode(input));
132 | }
133 |
134 | /**
135 | * Divides a number, represented as an array of bytes each containing a single
136 | * digit in the specified base, by the given divisor. The given number is
137 | * modified in-place to contain the quotient, and the return value is the
138 | * remainder.
139 | *
140 | * @param number the number to divide
141 | * @param firstDigit the index within the array of the first non-zero digit
142 | * (this is used for optimization by skipping the leading
143 | * zeros)
144 | * @param base the base in which the number's digits are represented (up
145 | * to 256)
146 | * @param divisor the number to divide by (up to 256)
147 | * @return the remainder of the division operation
148 | */
149 | private static byte divmod(byte[] number, int firstDigit, int base, int divisor) {
150 | // this is just long division which accounts for the base of the input digits
151 | int remainder = 0;
152 | for (int i = firstDigit; i < number.length; i++) {
153 | int digit = (int) number[i] & 0xFF;
154 | int temp = remainder * base + digit;
155 | number[i] = (byte) (temp / divisor);
156 | remainder = temp % divisor;
157 | }
158 | return (byte) remainder;
159 | }
160 | }
--------------------------------------------------------------------------------
/f2f-backend/src/main/java/com/f2f/backend/utilities/Constant.java:
--------------------------------------------------------------------------------
1 | package com.f2f.backend.utilities;
2 |
3 | public final class Constant {
4 | static final long ORIGIN_FILE_PART = 0L;
5 | }
6 |
--------------------------------------------------------------------------------
/f2f-backend/src/main/java/com/f2f/backend/utilities/FileIdGenerator.java:
--------------------------------------------------------------------------------
1 | package com.f2f.backend.utilities;
2 |
3 | import java.io.Serializable;
4 | import java.sql.Connection;
5 | import java.sql.ResultSet;
6 | import java.sql.SQLException;
7 | import java.sql.Statement;
8 |
9 | import org.hibernate.HibernateException;
10 | import org.hibernate.engine.spi.SharedSessionContractImplementor;
11 | import org.hibernate.id.IdentifierGenerator;
12 |
13 | import com.f2f.backend.ds.FilePart;
14 |
15 | public class FileIdGenerator implements IdentifierGenerator {
16 |
17 | @Override
18 | public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
19 | Connection connection = session.connection();
20 | FilePart file = (FilePart) object;
21 | final long originFileId = file.getOrigin();
22 | final int index = file.getIndex();
23 | try {
24 | Statement statement = connection.createStatement();
25 | if (index == 0 && originFileId == Constant.ORIGIN_FILE_PART) {
26 | ResultSet rs = statement.executeQuery("SELECT nextval('file_id_seq')");
27 | if (rs.next()) {
28 | Long id = rs.getLong(1);
29 | return id;
30 | }
31 | } else if (originFileId == Constant.ORIGIN_FILE_PART) {
32 | ResultSet rs = statement.executeQuery("SELECT currval('file_id_seq')");
33 | if (rs.next()) {
34 | Long id = rs.getLong(1);
35 | return id;
36 | }
37 | } else {
38 | return originFileId;
39 | }
40 |
41 | } catch (SQLException e) {
42 | e.printStackTrace();
43 | }
44 |
45 | return null;
46 | }
47 | }
--------------------------------------------------------------------------------
/f2f-backend/src/main/java/com/f2f/backend/utilities/PeerDetails.java:
--------------------------------------------------------------------------------
1 | package com.f2f.backend.utilities;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | @Component
9 | @Getter
10 | @Setter
11 | public class PeerDetails {
12 | Long peerId;
13 | Long channelId;
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/f2f-backend/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.datasource.url=jdbc:postgresql://192.168.1.50:5432/postgres
2 | spring.datasource.username=postgres
3 | spring.datasource.password=postgres
4 | spring.datasource.driverClassName=org.postgresql.Driver
5 | spring.jpa.generate-ddl=true
6 | spring.jpa.hibernate.ddl-auto=update
7 | server.port=5231
--------------------------------------------------------------------------------
/f2f-backend/src/test/java/com/f2f/backend/BackendApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.f2f.backend;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class BackendApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/f2f-frontend/.browserslistrc:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # For the full list of supported browsers by the Angular framework, please see:
6 | # https://angular.io/guide/browser-support
7 |
8 | # You can see what browsers were selected by your queries by running:
9 | # npx browserslist
10 |
11 | last 1 Chrome version
12 | last 1 Firefox version
13 | last 2 Edge major versions
14 | last 2 Safari major versions
15 | last 2 iOS major versions
16 | Firefox ESR
17 | not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
18 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
19 |
--------------------------------------------------------------------------------
/f2f-frontend/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/f2f-frontend/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/f2f-frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /tmp
5 | /out-tsc
6 | /dist
7 | # Only exists if Bazel was run
8 | /bazel-out
9 |
10 | # dependencies
11 | /node_modules
12 |
13 | # profiling files
14 | chrome-profiler-events*.json
15 | speed-measure-plugin*.json
16 |
17 | # IDEs and editors
18 | /.idea
19 | .project
20 | .classpath
21 | .c9/
22 | *.launch
23 | .settings/
24 | *.sublime-workspace
25 |
26 | # IDE - VSCode
27 | .vscode/*
28 | !.vscode/settings.json
29 | !.vscode/tasks.json
30 | !.vscode/launch.json
31 | !.vscode/extensions.json
32 | .history/*
33 |
34 | # misc
35 | /.sass-cache
36 | /connect.lock
37 | /coverage
38 | /libpeerconnection.log
39 | npm-debug.log
40 | yarn-error.log
41 | testem.log
42 | /typings
43 |
44 | # System Files
45 | .DS_Store
46 | Thumbs.db
47 |
--------------------------------------------------------------------------------
/f2f-frontend/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:latest
2 | COPY nginx.conf /etc/nginx/nginx.conf
3 | # COPY nginx.conf /etc/nginx/conf.d/default.conf
4 | RUN mkdir /etc/nginx/sites-enabled
5 | COPY f2f.nhvu95.com.conf /etc/nginx/sites-available/f2f.nhvu95.com
6 | #COPY E:/Angular/webrtc/f2f-frontend/dist/webrtc /usr/share/nginx/html/f2f.nhvu95.com
7 | RUN ln -s /etc/nginx/sites-available/f2f.nhvu95.com /etc/nginx/sites-enabled/
--------------------------------------------------------------------------------
/f2f-frontend/README.md:
--------------------------------------------------------------------------------
1 | # Webrtc
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.0.5.
4 |
5 | ## Sample
6 |
7 | Sample here: [File 2 Friends](https://f2f.nhvu95.com/)
8 |
9 | ## Development server
10 |
11 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
12 |
13 | ## Code scaffolding
14 |
15 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
16 |
17 | ## Build
18 |
19 | Run `npm run build` to build the project. The build artifacts will be stored in the `dist/webrtc` directory.
20 |
21 | ## Docker host
22 | After run build, to host in docker
23 |
24 | `docker compose up -d`
25 |
26 | ## Running unit tests
27 |
28 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
29 |
30 | ## Running end-to-end tests
31 |
32 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
33 |
34 | ## Further help
35 |
36 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
37 |
--------------------------------------------------------------------------------
/f2f-frontend/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "webrtc": {
7 | "projectType": "application",
8 | "schematics": {
9 | "@schematics/angular:class": {
10 | "skipTests": true
11 | },
12 | "@schematics/angular:component": {
13 | "inlineTemplate": true,
14 | "inlineStyle": true,
15 | "style": "scss",
16 | "skipTests": true
17 | },
18 | "@schematics/angular:directive": {
19 | "skipTests": true
20 | },
21 | "@schematics/angular:guard": {
22 | "skipTests": true
23 | },
24 | "@schematics/angular:interceptor": {
25 | "skipTests": true
26 | },
27 | "@schematics/angular:module": {
28 | "skipTests": true
29 | },
30 | "@schematics/angular:pipe": {
31 | "skipTests": true
32 | },
33 | "@schematics/angular:service": {
34 | "skipTests": true
35 | }
36 | },
37 | "root": "",
38 | "sourceRoot": "src",
39 | "prefix": "et",
40 | "architect": {
41 | "build": {
42 | "builder": "@angular-builders/custom-webpack:browser",
43 | "options": {
44 | "customWebpackConfig": {
45 | "path": "./webpack.config.ts",
46 | "mergeRules": {
47 | "externals": "replace"
48 | }
49 | },
50 | "outputPath": "dist/webrtc",
51 | "index": "src/index.html",
52 | "main": "src/main.ts",
53 | "polyfills": "src/polyfills.ts",
54 | "tsConfig": "tsconfig.app.json",
55 | "stylePreprocessorOptions": {
56 | "includePaths": [
57 | "src/assets"
58 | ]
59 | },
60 | "assets": [
61 | "src/favicon.ico",
62 | "src/assets",
63 | {
64 | "glob": "**/*",
65 | "input": "node_modules/@taiga-ui/icons/src",
66 | "output": "assets/taiga-ui/icons"
67 | }
68 | ],
69 | "styles": [
70 | "src/styles.scss",
71 | "node_modules/@taiga-ui/core/styles/taiga-ui-global.less",
72 | "node_modules/@taiga-ui/core/styles/taiga-ui-theme.less",
73 | "node_modules/@taiga-ui/core/styles/theme/variables.less",
74 | "node_modules/@taiga-ui/core/styles/theme/wrapper.less"
75 | ],
76 | "scripts": [],
77 | "vendorChunk": true,
78 | "extractLicenses": false,
79 | "buildOptimizer": false,
80 | "sourceMap": true,
81 | "optimization": false,
82 | "namedChunks": true
83 | },
84 | "configurations": {
85 | "production": {
86 | "fileReplacements": [
87 | {
88 | "replace": "src/environments/environment.ts",
89 | "with": "src/environments/environment.prod.ts"
90 | }
91 | ],
92 | "optimization": true,
93 | "outputHashing": "all",
94 | "sourceMap": false,
95 | "namedChunks": false,
96 | "extractLicenses": true,
97 | "vendorChunk": false,
98 | "buildOptimizer": false,
99 | "budgets": [
100 | {
101 | "type": "initial",
102 | "maximumWarning": "2mb",
103 | "maximumError": "5mb"
104 | },
105 | {
106 | "type": "anyComponentStyle",
107 | "maximumWarning": "6kb",
108 | "maximumError": "10kb"
109 | }
110 | ]
111 | }
112 | }
113 | },
114 | "serve": {
115 | "builder": "@angular-builders/custom-webpack:dev-server",
116 | "options": {
117 | "browserTarget": "webrtc:build"
118 | },
119 | "configurations": {
120 | "production": {
121 | "browserTarget": "webrtc:build:production"
122 | }
123 | }
124 | },
125 | "extract-i18n": {
126 | "builder": "@angular-devkit/build-angular:extract-i18n",
127 | "options": {
128 | "browserTarget": "webrtc:build"
129 | }
130 | },
131 | "test": {
132 | "builder": "@angular-devkit/build-angular:karma",
133 | "options": {
134 | "main": "src/test.ts",
135 | "polyfills": "src/polyfills.ts",
136 | "tsConfig": "tsconfig.spec.json",
137 | "karmaConfig": "karma.conf.js",
138 | "assets": [
139 | "src/favicon.ico",
140 | "src/assets",
141 | {
142 | "glob": "**/*",
143 | "input": "node_modules/@taiga-ui/icons/src",
144 | "output": "assets/taiga-ui/icons"
145 | }
146 | ],
147 | "styles": [
148 | "src/styles.scss",
149 | "node_modules/@taiga-ui/core/styles/taiga-ui-global.less",
150 | "node_modules/@taiga-ui/core/styles/taiga-ui-theme.less",
151 | "node_modules/@taiga-ui/core/styles/theme/variables.less",
152 | "node_modules/@taiga-ui/core/styles/theme/wrapper.less"
153 | ],
154 | "scripts": []
155 | }
156 | },
157 | "lint": {
158 | "builder": "@angular-devkit/build-angular:tslint",
159 | "options": {
160 | "tsConfig": [
161 | "tsconfig.app.json",
162 | "tsconfig.spec.json",
163 | "e2e/tsconfig.json"
164 | ],
165 | "exclude": [
166 | "**/node_modules/**"
167 | ]
168 | }
169 | },
170 | "e2e": {
171 | "builder": "@angular-devkit/build-angular:protractor",
172 | "options": {
173 | "protractorConfig": "e2e/protractor.conf.js",
174 | "devServerTarget": "webrtc:serve"
175 | },
176 | "configurations": {
177 | "production": {
178 | "devServerTarget": "webrtc:serve:production"
179 | }
180 | }
181 | },
182 | "deploy": {
183 | "builder": "angular-cli-ghpages:deploy",
184 | "options": {}
185 | }
186 | }
187 | }
188 | },
189 | "defaultProject": "webrtc",
190 | "cli": {
191 | "analytics": "455533e8-f542-4e03-bab4-f80f9d9ed4fc"
192 | }
193 | }
--------------------------------------------------------------------------------
/f2f-frontend/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "2.10.2"
2 | services:
3 | web-server:
4 | build: .
5 | ports:
6 | - "80:80"
7 | - "443:443"
8 | container_name: f2f-frontend-container
9 | image: "f2f-frontend-image"
10 | restart: unless-stopped
11 | volumes:
12 | - './dist/webrtc:/usr/share/nginx/html/f2f.nhvu95.com'
13 | - '../../certbot/nhvu95.com:/etc/nginx/cert'
14 |
--------------------------------------------------------------------------------
/f2f-frontend/e2e/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // Protractor configuration file, see link for more information
3 | // https://github.com/angular/protractor/blob/master/lib/config.ts
4 |
5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
6 |
7 | /**
8 | * @type { import("protractor").Config }
9 | */
10 | exports.config = {
11 | allScriptsTimeout: 11000,
12 | specs: [
13 | './src/**/*.e2e-spec.ts'
14 | ],
15 | capabilities: {
16 | browserName: 'chrome'
17 | },
18 | directConnect: true,
19 | baseUrl: 'http://localhost:4200/',
20 | framework: 'jasmine',
21 | jasmineNodeOpts: {
22 | showColors: true,
23 | defaultTimeoutInterval: 30000,
24 | print: function() {}
25 | },
26 | onPrepare() {
27 | require('ts-node').register({
28 | project: require('path').join(__dirname, './tsconfig.json')
29 | });
30 | jasmine.getEnv().addReporter(new SpecReporter({
31 | spec: {
32 | displayStacktrace: StacktraceOption.PRETTY
33 | }
34 | }));
35 | }
36 | };
--------------------------------------------------------------------------------
/f2f-frontend/e2e/src/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 | import { browser, logging } from 'protractor';
3 |
4 | describe('workspace-project App', () => {
5 | let page: AppPage;
6 |
7 | beforeEach(() => {
8 | page = new AppPage();
9 | });
10 |
11 | it('should display welcome message', () => {
12 | page.navigateTo();
13 | expect(page.getTitleText()).toEqual('webrtc app is running!');
14 | });
15 |
16 | afterEach(async () => {
17 | // Assert that there are no errors emitted from the browser
18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER);
19 | expect(logs).not.toContain(jasmine.objectContaining({
20 | level: logging.Level.SEVERE,
21 | } as logging.Entry));
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/f2f-frontend/e2e/src/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo(): PromiseF2F
22 |
24 |
29 |
147 |