aboutsummaryrefslogtreecommitdiff
path: root/central/src/main/java/moe/yuuta/dn42peering/admin/nodes/NodeAdminUI.java
blob: dd625ccdaf1af2d19a2e00ba5d60686fefd1e1b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package moe.yuuta.dn42peering.admin.nodes;

import edazdarevic.commons.net.CIDRUtils;
import io.vertx.core.Future;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.common.template.TemplateEngine;
import moe.yuuta.dn42peering.RPC;
import moe.yuuta.dn42peering.node.INodeService;
import moe.yuuta.dn42peering.node.Node;
import moe.yuuta.dn42peering.portal.FormException;
import moe.yuuta.dn42peering.portal.RenderingUtils;
import org.apache.commons.validator.routines.InetAddressValidator;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.net.Inet6Address;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class NodeAdminUI {
    public static void renderForm(@Nonnull TemplateEngine engine,
                                  @Nonnull INodeService nodeService,
                                  @Nonnull String asn,
                                  boolean newForm,
                                  @Nullable Node node,
                                  @Nullable List<String> errors,
                                  @Nonnull RoutingContext ctx) {
        final Map<String, Object> root = new HashMap<>();
        root.put("asn", asn);
        root.put("tunneling_method_wireguard", true);
        if (node != null) {
            root.put("id", node.getId());
            root.put("input_asn", node.getAsn());
            root.put("name", node.getName());
            root.put("ipv4", node.getDn42Ip4());
            root.put("ipv6", node.getDn42Ip6());
            root.put("ipv6_non_ll", node.getDn42Ip6NonLL());
            root.put("public_ip", node.getPublicIp());
            root.put("internal_ip", node.getInternalIp());
            root.put("internal_port", node.getInternalPort());
            root.put("notice", node.getNotice());
            root.put("tunneling_method_wireguard", node.isWireguard());
        }
        if(!newForm && node != null)
            root.put("action", "/admin/nodes/edit?id=" + node.getId());
        else
            root.put("action", "/admin/nodes/new");
        root.put("errors", errors);
        engine.render(root, newForm ? "admin/nodes/new.ftlh" : "admin/nodes/edit.ftlh",
                RenderingUtils.getGeneralRenderingHandler(ctx));
    }

    @Nonnull
    public static Future<Node> parseForm(@Nonnull INodeService nodeService,
                                         @Nonnull String authAsn,
                                         @Nonnull JsonObject form) {
        final List<String> errors = new ArrayList<>(10);
        final Node node = new Node();
        node.setAsn(form.getString("asn", authAsn));
        node.setName(form.getString("name"));
        node.setNotice(form.getString("notice"));
        node.setDn42Ip4(form.getString("ipv4"));
        node.setDn42Ip6(form.getString("ipv6"));
        node.setDn42Ip6NonLL(form.getString("ipv6_non_ll"));
        node.setInternalIp(form.getString("internal_ip"));
        node.setPublicIp(form.getString("public_ip"));
        try {
            String raw = form.getString("internal_port");
            if(raw == null || raw.isEmpty()) {
                node.setInternalPort(RPC.AGENT_PORT);
            } else {
                node.setInternalPort(Integer.parseInt(raw));
            }
        } catch (NumberFormatException e) {
            errors.add("Invalid internal port");
        }
        node.setWireguard(form.containsKey("tunneling_method_wireguard"));

        if(!node.getAsn().matches("[aA][sS]424242[0-9][0-9][0-9][0-9]"))
            errors.add("ASN is invalid");
        if(node.getName() == null || node.getName().trim().isEmpty())
            errors.add("No name supplied");
        try {
            if(node.getDn42Ip4() != null) {
                if (InetAddressValidator.getInstance().isValidInet4Address(node.getDn42Ip4())) {
                    if (!new CIDRUtils("172.20.0.0/14").isInRange(node.getDn42Ip4())) {
                        errors.add("DN42 IPv4 address is illegal. It must be a dn42 IPv4 address (172.20.x.x to 172.23.x.x).");
                    }
                } else
                    errors.add("DN42 IPv4 address is illegal. Cannot parse your address.");
            } else {
                errors.add("DN42 IPv4 address is not supplied");
            }
            if(node.getDn42Ip6() != null) {
                if (InetAddressValidator.getInstance().isValidInet6Address(node.getDn42Ip6())) {
                    if (new CIDRUtils("fd00::/8").isInRange(node.getDn42Ip6())) {
                        errors.add("DN42 IPv6 address is illegal. It must be a link-local IPv6 address.");
                    }
                } else
                    errors.add("DN42 Link Local IPv6 address is illegal. Cannot parse your address.");
            } else {
                errors.add("DN42 IPv6 Link Local address is not supplied");
            }
            if(node.getDn42Ip6NonLL() != null) {
                if (InetAddressValidator.getInstance().isValidInet6Address(node.getDn42Ip6NonLL())) {
                    if (!new CIDRUtils("fd00::/8").isInRange(node.getDn42Ip6NonLL()) ||
                            Inet6Address.getByName(node.getDn42Ip6NonLL()).isLinkLocalAddress()) {
                        errors.add("DN42 IPv6 address is illegal. It must be a dn42 IPv6 address.");
                    }
                } else
                    errors.add("IPv6 address is illegal. Cannot parse your address.");
            } else {
                errors.add("DN42 IPv6 address is not supplied");
            }
        } catch (IOException e) {
            return Future.failedFuture(e);
        }

        if(node.getInternalIp() == null) {
            errors.add("Internal IP is not supplied.");
        }

        if(node.getInternalPort() < 0 ||
            node.getInternalPort() > 65535) {
            errors.add("Internal Port is out of range. Supported range: [0, 65535].");
        }

        if(node.getPublicIp() == null || node.getPublicIp().isEmpty()) {
            errors.add("Public IP is not supplied.");
        }

        if(errors.isEmpty()) {
            return Future.succeededFuture(node);
        } else {
            return Future.failedFuture(new FormException(node, errors.toArray(new String[]{})));
        }
    }
}