IP名单新增IPv6和所有IP两种类型

This commit is contained in:
GoEdgeLab
2021-02-02 15:25:11 +08:00
parent cf196915e4
commit 21570f4e42
25 changed files with 681 additions and 322 deletions

View File

@@ -2,18 +2,42 @@ package utils
import (
"encoding/binary"
"math/big"
"net"
"regexp"
"strings"
)
// 将IP转换为整型
func IP2Long(ip string) uint32 {
func IP2Long(ip string) uint64 {
s := net.ParseIP(ip)
if s == nil {
if len(s) != 16 {
return 0
}
if len(s) == 16 {
return binary.BigEndian.Uint32(s[12:16])
if strings.Contains(ip, ":") { // IPv6
bigInt := big.NewInt(0)
bigInt.SetBytes(s.To16())
return bigInt.Uint64()
}
return binary.BigEndian.Uint32(s)
return uint64(binary.BigEndian.Uint32(s.To4()))
}
// 判断是否为IPv4
func IsIPv4(ip string) bool {
if !regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`).MatchString(ip) {
return false
}
if IP2Long(ip) == 0 {
return false
}
return true
}
// 判断是否为IPv6
func IsIPv6(ip string) bool {
if !strings.Contains(ip, ":") {
return false
}
return len(net.ParseIP(ip)) == net.IPv6len
}

View File

@@ -0,0 +1,85 @@
package utils
import (
"testing"
)
func TestIP2Long(t *testing.T) {
for _, ip := range []string{
"0.0.0.1",
"0.0.0.2",
"127.0.0.1",
"192.0.0.2",
"255.255.255.255",
"2001:db8:0:1::101",
"2001:db8:0:1::102",
"2406:8c00:0:3409:133:18:203:0",
"2406:8c00:0:3409:133:18:203:158",
"2406:8c00:0:3409:133:18:203:159",
"2406:8c00:0:3409:133:18:203:160",
} {
t.Log(ip, " -> ", IP2Long(ip))
}
}
func TestIsIPv4(t *testing.T) {
type testIP struct {
ip string
ok bool
}
for _, item := range []testIP{
{
ip: "1",
ok: false,
},
{
ip: "192.168.0.1",
ok: true,
},
{
ip: "1.1.0.1",
ok: true,
},
{
ip: "255.255.255.255",
ok: true,
},
{
ip: "192.168.0.1233",
ok: false,
},
} {
if IsIPv4(item.ip) != item.ok {
t.Fatal(item.ip, "should be", item.ok)
}
}
}
func TestIsIPv6(t *testing.T) {
type testIP struct {
ip string
ok bool
}
for _, item := range []testIP{
{
ip: "1",
ok: false,
},
{
ip: "2406:8c00:0:3409:133:18:203:158",
ok: true,
},
{
ip: "2406::8c00:0:3409:133:18:203:158",
ok: false,
},
{
ip: "2001:db8:0:1::101",
ok: true,
},
} {
if IsIPv6(item.ip) != item.ok {
t.Fatal(item.ip, "should be", item.ok)
}
}
}

View File

@@ -21,7 +21,7 @@ func (this *CreateIPPopupAction) RunGet(params struct {
FirewallPolicyId int64
Type string
}) {
this.Data["type"] = params.Type
this.Data["listType"] = params.Type
listId, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyIPListIdWithType(this.AdminContext(), params.FirewallPolicyId, params.Type)
if err != nil {
@@ -40,34 +40,47 @@ func (this *CreateIPPopupAction) RunPost(params struct {
IpTo string
ExpiredAt int64
Reason string
Type string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
// TODO 校验ListId所属用户
switch params.Type {
case "ipv4":
params.Must.
Field("ipFrom", params.IpFrom).
Require("请输入开始IP")
// 校验IP格式ipFrom/ipTo
ipFromLong := utils.IP2Long(params.IpFrom)
if len(params.IpFrom) > 0 {
if ipFromLong == 0 {
var ipFromLong uint64
if !utils.IsIPv4(params.IpFrom) {
this.Fail("请输入正确的开始IP")
}
}
ipFromLong = utils.IP2Long(params.IpFrom)
ipToLong := utils.IP2Long(params.IpTo)
if len(params.IpTo) > 0 {
if ipToLong == 0 {
var ipToLong uint64
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
ipToLong = utils.IP2Long(params.IpTo)
this.Fail("请输入正确的结束IP")
}
}
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
}
case "ipv6":
params.Must.
Field("ipFrom", params.IpFrom).
Require("请输入IP")
// 校验IP格式ipFrom
if !utils.IsIPv6(params.IpFrom) {
this.Fail("请输入正确的IPv6地址")
}
case "all":
params.IpFrom = "0.0.0.0"
}
createResp, err := this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
IpListId: params.ListId,
@@ -75,6 +88,7 @@ func (this *CreateIPPopupAction) RunPost(params struct {
IpTo: params.IpTo,
ExpiredAt: params.ExpiredAt,
Reason: params.Reason,
Type: params.Type,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -63,6 +63,7 @@ func (this *ListsAction) RunGet(params struct {
"ipTo": item.IpTo,
"expiredTime": expiredTime,
"reason": item.Reason,
"type": item.Type,
})
}
this.Data["items"] = itemMaps

View File

@@ -37,8 +37,11 @@ func (this *UpdateIPPopupAction) RunGet(params struct {
"ipTo": item.IpTo,
"expiredAt": item.ExpiredAt,
"reason": item.Reason,
"type": item.Type,
}
this.Data["type"] = item.Type
this.Show()
}
@@ -50,6 +53,7 @@ func (this *UpdateIPPopupAction) RunPost(params struct {
IpTo string
ExpiredAt int64
Reason string
Type string
Must *actions.Must
CSRF *actionutils.CSRF
@@ -59,28 +63,40 @@ func (this *UpdateIPPopupAction) RunPost(params struct {
// TODO 校验ItemId所属用户
switch params.Type {
case "ipv4":
params.Must.
Field("ipFrom", params.IpFrom).
Require("请输入开始IP")
// 校验IP格式ipFrom/ipTo
ipFromLong := utils.IP2Long(params.IpFrom)
if len(params.IpFrom) > 0 {
if ipFromLong == 0 {
var ipFromLong uint64
if !utils.IsIPv4(params.IpFrom) {
this.Fail("请输入正确的开始IP")
}
}
ipFromLong = utils.IP2Long(params.IpFrom)
ipToLong := utils.IP2Long(params.IpTo)
if len(params.IpTo) > 0 {
if ipToLong == 0 {
var ipToLong uint64
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
ipToLong = utils.IP2Long(params.IpTo)
this.Fail("请输入正确的结束IP")
}
}
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
}
case "ipv6":
params.Must.
Field("ipFrom", params.IpFrom).
Require("请输入IP")
// 校验IP格式ipFrom
if !utils.IsIPv6(params.IpFrom) {
this.Fail("请输入正确的IPv6地址")
}
case "all":
params.IpFrom = "0.0.0.0"
}
_, err := this.RPC().IPItemRPC().UpdateIPItem(this.AdminContext(), &pb.UpdateIPItemRequest{
IpItemId: params.ItemId,
@@ -88,6 +104,7 @@ func (this *UpdateIPPopupAction) RunPost(params struct {
IpTo: params.IpTo,
ExpiredAt: params.ExpiredAt,
Reason: params.Reason,
Type: params.Type,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -16,6 +16,7 @@ func (this *GroupsAction) Init() {
}
func (this *GroupsAction) RunGet(params struct {
ServerId int64
FirewallPolicyId int64
Type string
}) {
@@ -70,5 +71,13 @@ func (this *GroupsAction) RunGet(params struct {
this.Data["groups"] = groupMaps
// WAF是否启用
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["wafIsOn"] = webConfig.FirewallRef != nil && webConfig.FirewallRef.IsOn
this.Show()
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
type AllowListAction struct {
@@ -74,9 +75,19 @@ func (this *AllowListAction) RunGet(params struct {
"ipTo": item.IpTo,
"expiredTime": expiredTime,
"reason": item.Reason,
"type": item.Type,
"isExpired": item.ExpiredAt > 0 && item.ExpiredAt < time.Now().Unix(),
})
}
this.Data["items"] = itemMaps
// WAF是否启用
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["wafIsOn"] = webConfig.FirewallRef != nil && webConfig.FirewallRef.IsOn
this.Show()
}

View File

@@ -20,7 +20,7 @@ func (this *CreateIPPopupAction) RunGet(params struct {
ListId int64
Type string
}) {
this.Data["type"] = params.Type
this.Data["listType"] = params.Type
this.Data["listId"] = params.ListId
this.Show()
@@ -32,34 +32,47 @@ func (this *CreateIPPopupAction) RunPost(params struct {
IpTo string
ExpiredAt int64
Reason string
Type string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
// TODO 校验ListId所属用户
switch params.Type {
case "ipv4":
params.Must.
Field("ipFrom", params.IpFrom).
Require("请输入开始IP")
// 校验IP格式ipFrom/ipTo
ipFromLong := utils.IP2Long(params.IpFrom)
if len(params.IpFrom) > 0 {
if ipFromLong == 0 {
var ipFromLong uint64
if !utils.IsIPv4(params.IpFrom) {
this.Fail("请输入正确的开始IP")
}
}
ipFromLong = utils.IP2Long(params.IpFrom)
ipToLong := utils.IP2Long(params.IpTo)
if len(params.IpTo) > 0 {
if ipToLong == 0 {
var ipToLong uint64
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
ipToLong = utils.IP2Long(params.IpTo)
this.Fail("请输入正确的结束IP")
}
}
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
}
case "ipv6":
params.Must.
Field("ipFrom", params.IpFrom).
Require("请输入IP")
// 校验IP格式ipFrom
if !utils.IsIPv6(params.IpFrom) {
this.Fail("请输入正确的IPv6地址")
}
case "all":
params.IpFrom = "0.0.0.0"
}
createResp, err := this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
IpListId: params.ListId,
@@ -67,6 +80,7 @@ func (this *CreateIPPopupAction) RunPost(params struct {
IpTo: params.IpTo,
ExpiredAt: params.ExpiredAt,
Reason: params.Reason,
Type: params.Type,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -6,6 +6,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
type DenyListAction struct {
@@ -74,9 +75,19 @@ func (this *DenyListAction) RunGet(params struct {
"ipTo": item.IpTo,
"expiredTime": expiredTime,
"reason": item.Reason,
"type": item.Type,
"isExpired": item.ExpiredAt > 0 && item.ExpiredAt < time.Now().Unix(),
})
}
this.Data["items"] = itemMaps
// WAF是否启用
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["wafIsOn"] = webConfig.FirewallRef != nil && webConfig.FirewallRef.IsOn
this.Show()
}

View File

@@ -37,8 +37,11 @@ func (this *UpdateIPPopupAction) RunGet(params struct {
"ipTo": item.IpTo,
"expiredAt": item.ExpiredAt,
"reason": item.Reason,
"type": item.Type,
}
this.Data["type"] = item.Type
this.Show()
}
@@ -49,6 +52,7 @@ func (this *UpdateIPPopupAction) RunPost(params struct {
IpTo string
ExpiredAt int64
Reason string
Type string
Must *actions.Must
CSRF *actionutils.CSRF
@@ -58,28 +62,40 @@ func (this *UpdateIPPopupAction) RunPost(params struct {
// TODO 校验ItemId所属用户
switch params.Type {
case "ipv4":
params.Must.
Field("ipFrom", params.IpFrom).
Require("请输入开始IP")
// 校验IP格式ipFrom/ipTo
ipFromLong := utils.IP2Long(params.IpFrom)
if len(params.IpFrom) > 0 {
if ipFromLong == 0 {
var ipFromLong uint64
if !utils.IsIPv4(params.IpFrom) {
this.Fail("请输入正确的开始IP")
}
}
ipFromLong = utils.IP2Long(params.IpFrom)
ipToLong := utils.IP2Long(params.IpTo)
if len(params.IpTo) > 0 {
if ipToLong == 0 {
var ipToLong uint64
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
ipToLong = utils.IP2Long(params.IpTo)
this.Fail("请输入正确的结束IP")
}
}
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
}
case "ipv6":
params.Must.
Field("ipFrom", params.IpFrom).
Require("请输入IP")
// 校验IP格式ipFrom
if !utils.IsIPv6(params.IpFrom) {
this.Fail("请输入正确的IPv6地址")
}
case "all":
params.IpFrom = "0.0.0.0"
}
_, err := this.RPC().IPItemRPC().UpdateIPItem(this.AdminContext(), &pb.UpdateIPItemRequest{
IpItemId: params.ItemId,
@@ -87,6 +103,7 @@ func (this *UpdateIPPopupAction) RunPost(params struct {
IpTo: params.IpTo,
ExpiredAt: params.ExpiredAt,
Reason: params.Reason,
Type: params.Type,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -1,5 +1,15 @@
Vue.component("datetime-input", {
props: ["v-name", "v-timestamp"],
mounted: function () {
let that = this
teaweb.datepicker(this.$refs.dayInput, function (v) {
that.day = v
that.hour = "23"
that.minute = "59"
that.second = "59"
that.change()
})
},
data: function () {
let timestamp = this.vTimestamp
if (timestamp != null) {
@@ -122,7 +132,7 @@ Vue.component("datetime-input", {
this.hasSecondError = false
date.setSeconds(second)
this.timestamp = Math.ceil(date.getTime() / 1000)
this.timestamp = parseInt(date.getTime() / 1000)
},
leadingZero: function (s, l) {
if (l <= s.length) {
@@ -138,7 +148,7 @@ Vue.component("datetime-input", {
<input type="hidden" :name="vName" :value="timestamp"/>
<div class="ui fields inline" style="padding: 0; margin:0">
<div class="ui field" :class="{error: hasDayError}">
<input type="text" v-model="day" placeholder="YYYY-MM-DD" style="width:8em" maxlength="10" @input="change"/>
<input type="text" v-model="day" placeholder="YYYY-MM-DD" style="width:8.6em" maxlength="10" @input="change" ref="dayInput"/>
</div>
<div class="ui field" :class="{error: hasHourError}"><input type="text" v-model="hour" maxlength="2" style="width:4em" placeholder="时" @input="change"/></div>
<div class="ui field">:</div>

View File

@@ -0,0 +1,58 @@
Vue.component("ip-list-table", {
props: ["v-items"],
data: function () {
return {
items: this.vItems
}
},
methods: {
updateItem: function (itemId) {
this.$emit("update-item", itemId)
},
deleteItem: function (itemId) {
this.$emit("delete-item", itemId)
}
},
template: `<div>
<table class="ui table selectable celled" v-if="items.length > 0">
<thead>
<tr>
<th style="width:18em">IP</th>
<th>类型</th>
<th>过期时间</th>
<th>备注</th>
<th class="two op">操作</th>
</tr>
</thead>
<tr v-for="item in items">
<td>
<span v-if="item.type != 'all'">{{item.ipFrom}}<span v-if="item.ipTo.length > 0"> - {{item.ipTo}}</span></span>
<span v-else class="disabled">*</span>
</td>
<td>
<span v-if="item.type.length == 0">IPv4</span>
<span v-else-if="item.type == 'ipv4'">IPv4</span>
<span v-else-if="item.type == 'ipv6'">IPv6</span>
<span v-else-if="item.type == 'all'"><strong>所有IP</strong></span>
</td>
<td>
<div v-if="item.expiredTime.length > 0">
{{item.expiredTime}}
<div v-if="item.isExpired" style="margin-top: 0.5em">
<span class="ui label tiny basic red">已过期</span>
</div>
</div>
<span v-else class="disabled">不过期</span>
</td>
<td>
<span v-if="item.reason.length > 0">{{item.reason}}</span>
<span v-else class="disabled">-</span>
</td>
<td>
<a href="" @click.prevent="updateItem(item.id)">修改</a> &nbsp;
<a href="" @click.prevent="deleteItem(item.id)">删除</a>
</td>
</tr>
</table>
</div>`
})

View File

@@ -50,7 +50,41 @@ window.teaweb = {
return true;
},
loadJS: function (file, callback) {
let element = document.createElement("script")
element.setAttribute("type", "text/javascript")
element.setAttribute("src", file)
if (typeof callback == "function") {
element.addEventListener("load", callback)
}
document.head.append(element)
},
loadCSS: function (file, callback) {
let element = document.createElement("link")
element.setAttribute("rel", "stylesheet")
element.setAttribute("type", "text/css")
element.setAttribute("href", file)
if (typeof callback == "function") {
element.addEventListener("load", callback)
}
document.head.append(element)
},
datepicker: function (element, callback) {
// 加载
if (typeof Pikaday == "undefined") {
let that = this
this.loadJS("/js/moment.min.js")
this.loadJS("/js/pikaday.js", function () {
that.datepicker(element, callback)
})
this.loadCSS("/js/pikaday.css")
this.loadCSS("/js/pikaday.theme.css")
this.loadCSS("/js/pikaday.triangle.css")
return
}
if (typeof (element) == "string") {
element = document.getElementById(element);
}

View File

@@ -9,7 +9,23 @@
<csrf-token></csrf-token>
<table class="ui table definition selectable">
<tr>
<td class="title">开始IP *</td>
<td class="title">类型 *</td>
<td>
<select class="ui dropdown auto-width" name="type" v-model="type">
<option value="ipv4">IPv4</option>
<option value="ipv6">IPv6</option>
<option value="all">所有IP</option>
</select>
<p class="comment" v-if="type == 'ipv4'">单个IPv4或一个IPv4范围。</p>
<p class="comment" v-if="type == 'ipv6'">单个IPv6。</p>
<p class="comment" v-if="type == 'all'">允许或禁用所有的IP。</p>
</td>
</tr>
<!-- IPv4 -->
<tbody v-if="type == 'ipv4'">
<tr>
<td>开始IP *</td>
<td>
<input type="text" name="ipFrom" maxlength="64" placeholder="x.x.x.x" ref="focus"/>
</td>
@@ -21,6 +37,18 @@
<p class="comment">表示IP段的时候需要填写此项。</p>
</td>
</tr>
</tbody>
<!-- IPv6 -->
<tbody v-if="type == 'ipv6'">
<tr>
<td>IP *</td>
<td>
<input type="text" name="ipFrom" maxlength="64" placeholder="x:x:x:x:x:x:x:x" ref="focus"/>
<p class="comment">IPv6地址比如 1406:3c00:0:2409:13:58:103:15</p>
</td>
</tr>
</tbody>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.type = "ipv4"
})

View File

@@ -5,30 +5,6 @@
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
<table class="ui table selectable celled" v-if="items.length > 0">
<thead>
<tr>
<th>IP</th>
<th>过期时间</th>
<th>备注</th>
<th class="two op">操作</th>
</tr>
</thead>
<tr v-for="item in items">
<td>{{item.ipFrom}}<span v-if="item.ipTo.length > 0"> - {{item.ipTo}}</span></td>
<td>
<span v-if="item.expiredTime.length > 0">{{item.expiredTime}}</span>
<span v-else class="disabled">不过期</span>
</td>
<td>
<span v-if="item.reason.length > 0">{{item.reason}}</span>
<span v-else class="disabled">-</span>
</td>
<td>
<a href="" @click.prevent="updateItem(item.id)">修改</a> &nbsp;
<a href="" @click.prevent="deleteItem(item.id)">删除</a>
</td>
</tr>
</table>
<ip-list-table v-if="items.length > 0" :v-items="items" @update-item="updateItem" @delete-item="deleteItem"></ip-list-table>
<div class="page" v-html="page"></div>

View File

@@ -5,10 +5,27 @@
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
<input type="hidden" name="itemId" :value="item.id"/>
<input type="hidden" name="type" :value="item.type"/>
<csrf-token></csrf-token>
<table class="ui table definition selectable">
<tr>
<td class="title">开始IP *</td>
<td class="title">类型 *</td>
<td>
<!-- 类型不允许修改 -->
<span v-if="item.type == 'ipv4'">IPv4</span>
<span v-if="item.type == 'ipv6'">IPv6</span>
<span v-if="item.type == 'all'">所有IP</span>
<p class="comment" v-if="type == 'ipv4'">单个IPv4或一个IPv4范围。</p>
<p class="comment" v-if="type == 'ipv6'">单个IPv6。</p>
<p class="comment" v-if="type == 'all'">允许或禁用所有的IP。</p>
</td>
</tr>
<!-- IPv4 -->
<tbody v-if="type == 'ipv4'">
<tr>
<td>开始IP *</td>
<td>
<input type="text" name="ipFrom" maxlength="64" placeholder="x.x.x.x" ref="focus" v-model="item.ipFrom"/>
</td>
@@ -20,6 +37,18 @@
<p class="comment">表示IP段的时候需要填写此项。</p>
</td>
</tr>
</tbody>
<!-- IPv6 -->
<tbody v-if="type == 'ipv6'">
<tr>
<td>IP *</td>
<td>
<input type="text" name="ipFrom" maxlength="64" placeholder="x:x:x:x:x:x:x:x" ref="focus" v-model="item.ipFrom"/>
<p class="comment">IPv6地址比如 1406:3c00:0:2409:13:58:103:15</p>
</td>
</tr>
</tbody>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>

View File

@@ -8,6 +8,8 @@
<a href="" class="item" @click.prevent="createGroup(type)">[添加分组]</a>
</second-menu>
<p class="ui message warning" v-if="!wafIsOn">当前WAF未启用设置将在<a :href="'/servers/server/settings/waf?serverId=' + serverId">[启用]</a>后生效。</p>
<p class="comment" v-if="groups.length == 0">暂时还没有规则分组。</p>
<table class="ui table selectable celled" v-if="groups.length > 0" id="sortable-table">

View File

@@ -13,33 +13,10 @@
<span class="item">ID: {{listId}} &nbsp; <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
</second-menu>
<p class="comment" v-if="items.length == 0">暂时还没有IP</p>
<p class="ui message warning" v-if="!wafIsOn">当前WAF未启用设置将在<a :href="'/servers/server/settings/waf?serverId=' + serverId">[启用]</a>后生效</p>
<table class="ui table selectable celled" v-if="items.length > 0">
<thead>
<tr>
<th>IP</th>
<th>过期时间</th>
<th>备注</th>
<th class="two op">操作</th>
</tr>
</thead>
<tr v-for="item in items">
<td>{{item.ipFrom}}<span v-if="item.ipTo.length > 0"> - {{item.ipTo}}</span></td>
<td>
<span v-if="item.expiredTime.length > 0">{{item.expiredTime}}</span>
<span v-else class="disabled">不过期</span>
</td>
<td>
<span v-if="item.reason.length > 0">{{item.reason}}</span>
<span v-else class="disabled">-</span>
</td>
<td>
<a href="" @click.prevent="updateItem(item.id)">修改</a> &nbsp;
<a href="" @click.prevent="deleteItem(item.id)">删除</a>
</td>
</tr>
</table>
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
<ip-list-table v-if="items.length > 0" :v-items="items" @update-item="updateItem" @delete-item="deleteItem"></ip-list-table>
<div class="page" v-html="page"></div>
{$end}

View File

@@ -1,7 +1,7 @@
Tea.context(function () {
this.updateItem = function (itemId) {
teaweb.popup(Tea.url(".updateIPPopup?listId=" + this.listId, {itemId: itemId}), {
height: "23em",
height: "24em",
callback: function () {
teaweb.success("保存成功", function () {
teaweb.reload()
@@ -27,7 +27,7 @@ Tea.context(function () {
*/
this.createIP = function (type) {
teaweb.popup("/servers/server/settings/waf/ipadmin/createIPPopup?listId=" + this.listId + '&type=' + type, {
height: "23em",
height: "24em",
callback: function () {
window.location.reload()
}

View File

@@ -1,14 +1,30 @@
{$layout "layout_popup"}
<h3 v-if="type == 'white'">添加IP到白名单</h3>
<h3 v-if="type == 'black'">添加IP到黑名单</h3>
<h3 v-if="listType == 'white'">添加IP到白名单</h3>
<h3 v-if="listType == 'black'">添加IP到黑名单</h3>
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="listId" :value="listId"/>
<csrf-token></csrf-token>
<table class="ui table definition selectable">
<tr>
<td class="title">开始IP *</td>
<td class="title">类型 *</td>
<td>
<select class="ui dropdown auto-width" name="type" v-model="type">
<option value="ipv4">IPv4</option>
<option value="ipv6">IPv6</option>
<option value="all">所有IP</option>
</select>
<p class="comment" v-if="type == 'ipv4'">单个IPv4或一个IPv4范围。</p>
<p class="comment" v-if="type == 'ipv6'">单个IPv6。</p>
<p class="comment" v-if="type == 'all'">允许或禁用所有的IP。</p>
</td>
</tr>
<!-- IPv4 -->
<tbody v-if="type == 'ipv4'">
<tr>
<td>开始IP *</td>
<td>
<input type="text" name="ipFrom" maxlength="64" placeholder="x.x.x.x" ref="focus"/>
</td>
@@ -20,6 +36,19 @@
<p class="comment">表示IP段的时候需要填写此项。</p>
</td>
</tr>
</tbody>
<!-- IPv6 -->
<tbody v-if="type == 'ipv6'">
<tr>
<td>IP *</td>
<td>
<input type="text" name="ipFrom" maxlength="64" placeholder="x:x:x:x:x:x:x:x" ref="focus"/>
<p class="comment">IPv6地址比如 1406:3c00:0:2409:13:58:103:15</p>
</td>
</tr>
</tbody>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>
@@ -37,6 +66,6 @@
</tr>
</tbody>
</table>
<p class="comment">添加后将会在5分钟生效。</p>
<p class="comment">添加后将会在5分钟生效。</p>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.type = "ipv4"
})

View File

@@ -13,33 +13,10 @@
<span class="item">ID: {{listId}} &nbsp; <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
</second-menu>
<p class="comment" v-if="items.length == 0">暂时还没有IP</p>
<p class="ui message warning" v-if="!wafIsOn">当前WAF未启用设置将在<a :href="'/servers/server/settings/waf?serverId=' + serverId">[启用]</a>后生效</p>
<table class="ui table selectable celled" v-if="items.length > 0">
<thead>
<tr>
<th>IP</th>
<th>过期时间</th>
<th>备注</th>
<th class="two op">操作</th>
</tr>
</thead>
<tr v-for="item in items">
<td>{{item.ipFrom}}<span v-if="item.ipTo.length > 0"> - {{item.ipTo}}</span></td>
<td>
<span v-if="item.expiredTime.length > 0">{{item.expiredTime}}</span>
<span v-else class="disabled">不过期</span>
</td>
<td>
<span v-if="item.reason.length > 0">{{item.reason}}</span>
<span v-else class="disabled">-</span>
</td>
<td>
<a href="" @click.prevent="updateItem(item.id)">修改</a> &nbsp;
<a href="" @click.prevent="deleteItem(item.id)">删除</a>
</td>
</tr>
</table>
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
<ip-list-table v-if="items.length > 0" :v-items="items" @update-item="updateItem" @delete-item="deleteItem"></ip-list-table>
<div class="page" v-html="page"></div>
{$end}

View File

@@ -1,7 +1,7 @@
Tea.context(function () {
this.updateItem = function (itemId) {
teaweb.popup(Tea.url(".updateIPPopup?listId=" + this.listId, {itemId: itemId}), {
height: "23em",
height: "24em",
callback: function () {
teaweb.success("保存成功", function () {
teaweb.reload()
@@ -27,7 +27,7 @@ Tea.context(function () {
*/
this.createIP = function (type) {
teaweb.popup("/servers/server/settings/waf/ipadmin/createIPPopup?listId=" + this.listId + '&type=' + type, {
height: "23em",
height: "24em",
callback: function () {
window.location.reload()
}

View File

@@ -4,10 +4,27 @@
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="itemId" :value="item.id"/>
<input type="hidden" name="type" :value="item.type"/>
<csrf-token></csrf-token>
<table class="ui table definition selectable">
<tr>
<td class="title">开始IP *</td>
<td class="title">类型 *</td>
<td>
<!-- 类型不允许修改 -->
<span v-if="item.type == 'ipv4'">IPv4</span>
<span v-if="item.type == 'ipv6'">IPv6</span>
<span v-if="item.type == 'all'">所有IP</span>
<p class="comment" v-if="type == 'ipv4'">单个IPv4或一个IPv4范围。</p>
<p class="comment" v-if="type == 'ipv6'">单个IPv6。</p>
<p class="comment" v-if="type == 'all'">允许或禁用所有的IP。</p>
</td>
</tr>
<!-- IPv4 -->
<tbody v-if="type == 'ipv4'">
<tr>
<td>开始IP *</td>
<td>
<input type="text" name="ipFrom" maxlength="64" placeholder="x.x.x.x" ref="focus" v-model="item.ipFrom"/>
</td>
@@ -19,6 +36,19 @@
<p class="comment">表示IP段的时候需要填写此项。</p>
</td>
</tr>
</tbody>
<!-- IPv6 -->
<tbody v-if="type == 'ipv6'">
<tr>
<td>IP *</td>
<td>
<input type="text" name="ipFrom" maxlength="64" placeholder="x:x:x:x:x:x:x:x" ref="focus" v-model="item.ipFrom"/>
<p class="comment">IPv6地址比如 1406:3c00:0:2409:13:58:103:15</p>
</td>
</tr>
</tbody>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>