Commit d1f6ed4a authored by halcyon's avatar halcyon

增加日志查看功能

parents 1a266f0b 95fbdce9

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

......@@ -5,6 +5,7 @@ import sys
import os
import select
import time
from datetime import datetime
import paramiko
import struct
import fcntl
......@@ -34,7 +35,7 @@ except ImportError:
time.sleep(3)
sys.exit()
BASE_DIR = os.path.dirname(__file__)
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
CONF = ConfigParser()
CONF.read(os.path.join(BASE_DIR, 'jumpserver.conf'))
LOG_DIR = os.path.join(BASE_DIR, 'logs')
......@@ -155,7 +156,7 @@ def log_record(username, host):
except IOError:
raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir)
log = Log(user=user, asset=asset, log_path=log_file_path, start_time=timestamp_start, pid=pid)
log = Log(user=user, asset=asset, log_path=log_file_path, start_time=datetime.now(), pid=pid)
log.save()
return log_file, log
......@@ -200,7 +201,7 @@ def posix_shell(chan, username, host):
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
log_file.close()
log.is_finished = True
log.end_time = timestamp_end
log.end_time = datetime.now()
log.save()
......
......@@ -8,10 +8,10 @@ class Log(models.Model):
user = models.ForeignKey(User)
asset = models.ForeignKey(Asset)
log_path = models.CharField(max_length=100)
start_time = models.IntegerField()
start_time = models.DateTimeField(null=True)
pid = models.IntegerField(max_length=10)
is_finished = models.BooleanField(default=False)
end_time = models.IntegerField(blank=True, null=True)
end_time = models.DateTimeField(null=True)
def __unicode__(self):
return self.log_path
\ No newline at end of file
# coding:utf-8
from django.conf.urls import patterns, include, url
from jlog.views import *
urlpatterns = patterns('',
url(r'^$', jlog_list),
url(r'^log_list/$', jlog_list),
url(r'^log_kill/(\d+)', jlog_kill),
)
from django.shortcuts import render
# coding:utf-8
import os
import ConfigParser
from datetime import datetime
from django.http import HttpResponseRedirect
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.core.paginator import Paginator, EmptyPage
# Create your views here.
from connect import BASE_DIR
from jlog.models import Log
CONF = ConfigParser.ConfigParser()
CONF.read('%s/jumpserver.conf' % BASE_DIR)
def jlog_list(request):
header_title, path1, path2 = u'查看日志 | Log List.', u'查看日志', u'日志列表'
online = Log.objects.filter(is_finished=0)
offline = Log.objects.filter(is_finished=1)
web_socket_host = CONF.get('websocket', 'web_socket_host')
return render_to_response('jlog/log_list.html',locals())
def jlog_kill(request, offset):
pid = offset
if pid:
os.kill(int(pid), 9)
Log.objects.filter(pid=pid).update(is_finished=1, end_time=datetime.now())
return render_to_response('jlog/log_list.html', locals())
\ No newline at end of file
......@@ -18,6 +18,9 @@ base_dn = dc=jumpserver,dc=org
root_dn = cn=admin,dc=jumpserver,dc=org
root_pw = secret234
[websocket]
web_socket_host = 127.0.0.1:3000
[web]
key = 88aaaf7ffe3c6c04
......@@ -10,5 +10,6 @@ urlpatterns = patterns('',
(r'^base/$', 'jumpserver.views.base'),
(r'^juser/', include('juser.urls')),
(r'^jperm/', include('jpermission.urls')),
url(r'^jasset/', include('jasset.urls')),
(r'^jasset/', include('jasset.urls')),
(r'^jlog/', include('jlog.urls')),
)
......@@ -13,4 +13,7 @@ urlpatterns = patterns('juser.views',
(r'^user_detail/$', 'user_detail'),
(r'^user_del/$', 'user_del'),
(r'^user_edit/$', 'user_edit'),
(r'^group_detail/$', 'group_detail'),
(r'^group_del/$', 'group_del'),
(r'^group_edit/$', 'group_edit'),
)
......@@ -147,11 +147,60 @@ def group_add(request):
def group_list(request):
header_title, path1, path2 = '查看属组 | Add Group', 'juser', 'group_list'
groups = UserGroup.objects.all()
header_title, path1, path2 = '查看属组 | Show Group', 'juser', 'group_list'
groups = contact_list = UserGroup.objects.all().order_by('id')
p = paginator = Paginator(contact_list, 10)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
contacts = paginator.page(page)
except (EmptyPage, InvalidPage):
contacts = paginator.page(paginator.num_pages)
return render_to_response('juser/group_list.html', locals())
def group_detail(request):
group_id = request.GET.get('id', None)
if not group_id:
return HttpResponseRedirect('/')
group = UserGroup.objects.get(id=group_id)
return render_to_response('juser/group_detail.html', locals())
def group_del(request):
group_id = request.GET.get('id', None)
if not group_id:
return HttpResponseRedirect('/')
group = UserGroup.objects.get(id=group_id)
group.delete()
return HttpResponseRedirect('/juser/group_list/', locals())
def group_edit(request):
error = ''
msg = ''
header_title, path1, path2 = '修改属组 | Edit Group', 'juser', 'group_edit'
if request.method == 'GET':
group_id = request.GET.get('id', None)
group = UserGroup.objects.get(id=group_id)
group_name = group.name
comment = group.comment
return render_to_response('juser/group_add.html', locals())
else:
group_id = request.POST.get('group_id', None)
group_name = request.POST.get('group_name', None)
comment = request.POST.get('comment', '')
group = UserGroup.objects.filter(id=group_id)
group.update(name=group_name, comment=comment)
return HttpResponseRedirect('/juser/group_list/')
def user_list(request):
user_role = {'SU': u'超级管理员', 'GA': u'组管理员', 'CU': u'普通用户'}
header_title, path1, path2 = '查看用户 | Show User', 'juser', 'user_list'
......@@ -171,30 +220,30 @@ def user_list(request):
def user_detail(request):
username = request.GET.get('username', None)
if not username:
user_id = request.GET.get('id', None)
if not user_id:
return HttpResponseRedirect('/')
user = User.objects.get(username=username)
user = User.objects.get(id=user_id)
return render_to_response('juser/user_detail.html', locals())
def user_del(request):
username = request.GET.get('username', None)
if not username:
user_id = request.GET.get('id', None)
if not user_id:
return HttpResponseRedirect('/')
user = User.objects.get(username=username)
user = User.objects.get(id=user_id)
user.delete()
return HttpResponseRedirect('/juser/user_list/', locals())
def user_edit(request):
header_title, path1, path2 = '编辑用户 | Edit User', 'juser', 'user_edit'
hidden = "hidden"
readonly = "readonly"
if request.method == 'GET':
username = request.GET.get('username', None)
if not username:
user_id = request.GET.get('id', None)
if not user_id:
return HttpResponseRedirect('/')
user = User.objects.get(username=username)
user = User.objects.get(id=user_id)
username = user.username
password = user.password
ssh_key_pwd1 = user.ssh_key_pwd1
......
PS1='[\u@192.168.196.73 \W]\$ '
Last login: Sat Jan 24 05:19:23 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.196.73 \W]\$ '
[halcyon@192.168.196.73 ~]$ clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
Login 192.168.196.73 done. Enjoy it.
[halcyon@192.168.196.73 ~]$ ifconfig
eth0 Link encap:Ethernet HWaddr 08:00:27:AE:97:4F
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feae:974f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:607 errors:0 dropped:0 overruns:0 frame:0
TX packets:426 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:62277 (60.8 KiB) TX bytes:52684 (51.4 KiB)
eth1 Link encap:Ethernet HWaddr 08:00:27:B6:17:22
inet addr:192.168.196.73 Bcast:192.168.199.255 Mask:255.255.248.0
inet6 addr: fe80::a00:27ff:feb6:1722/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:28140 errors:0 dropped:0 overruns:0 frame:0
TX packets:170 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1908800 (1.8 MiB) TX bytes:20462 (19.9 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ hah
-bash: hah: command not found
[halcyon@192.168.196.73 ~]$ [halcyon@192.168.196.73 ~ ~]$ [halcyon@192.168.196.73 ~]$ [halcyon@192.168.196.73 ~]$ [halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ exit
logout
PS1='[\u@192.168.196.73 \W]\$ '
Last login: Sat Jan 24 06:59:23 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.196.73 \W]\$ '
[halcyon@192.168.196.73 ~]$ clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
Login 192.168.196.73 done. Enjoy it.
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ ifocnfigconfig
eth0 Link encap:Ethernet HWaddr 08:00:27:AE:97:4F
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feae:974f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:616 errors:0 dropped:0 overruns:0 frame:0
TX packets:431 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:63001 (61.5 KiB) TX bytes:53086 (51.8 KiB)
eth1 Link encap:Ethernet HWaddr 08:00:27:B6:17:22
inet addr:192.168.196.73 Bcast:192.168.199.255 Mask:255.255.248.0
inet6 addr: fe80::a00:27ff:feb6:1722/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:32903 errors:0 dropped:0 overruns:0 frame:0
TX packets:261 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2226913 (2.1 MiB) TX bytes:31635 (30.8 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ pwd
/home/halcyon
[halcyon@192.168.196.73 ~]$ exit
logout
PS1='[\u@192.168.196.73 \W]\$ '
Last login: Sat Jan 24 07:15:07 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.196.73 \W]\$ '
[halcyon@192.168.196.73 ~]$ clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
Login 192.168.196.73 done. Enjoy it.
[halcyon@192.168.196.73 ~]$ exit
logout
PS1='[\u@192.168.196.73 \W]\$ '
Last login: Sat Jan 24 07:37:41 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.196.73 \W]\$ '
[halcyon@192.168.196.73 ~]$ clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
Login 192.168.196.73 done. Enjoy it.
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ exit
logout
PS1='[\u@192.168.196.73 \W]\$ '
Last login: Sat Jan 24 07:38:42 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.196.73 \W]\$ '
[halcyon@192.168.196.73 ~]$ clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
Login 192.168.196.73 done. Enjoy it.
[halcyon@192.168.196.73 ~]$ exit
logout
PS1='[\u@192.168.196.73 \W]\$ '
Last login: Sat Jan 24 07:42:24 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.196.73 \W]\$ '
[halcyon@192.168.196.73 ~]$ clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
Login 192.168.196.73 done. Enjoy it.
[halcyon@192.168.196.73 ~]$ exit
logout
PS1='[\u@192.168.196.73 \W]\$ '
Last login: Sat Jan 24 07:50:33 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.196.73 \W]\$ '
[halcyon@192.168.196.73 ~]$ clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
Login 192.168.196.73 done. Enjoy it.
[halcyon@192.168.196.73 ~]$ exit
logout
PS1='[\u@192.168.196.73 \W]\$ '
Last login: Sat Jan 24 07:54:52 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.196.73 \W]\$ '
[halcyon@192.168.196.73 ~]$ clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
Login 192.168.196.73 done. Enjoy it.
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ exit
logout
PS1='[\u@192.168.196.73 \W]\$ '
Last login: Sat Jan 24 08:04:04 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.196.73 \W]\$ '
[halcyon@192.168.196.73 ~]$ clear;echo -e '\033[32mLogin 192.168.196.73 done. Enjoy it.\033[0m'
Login 192.168.196.73 done. Enjoy it.
[halcyon@192.168.196.73 ~]$ pwd
/home/halcyon
[halcyon@192.168.196.73 ~]$ heh
-bash: heh: command not found
[halcyon@192.168.196.73 ~]$ ls
[halcyon@192.168.196.73 ~]$ ifconfig
eth0 Link encap:Ethernet HWaddr 08:00:27:AE:97:4F
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feae:974f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:616 errors:0 dropped:0 overruns:0 frame:0
TX packets:431 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:63001 (61.5 KiB) TX bytes:53086 (51.8 KiB)
eth1 Link encap:Ethernet HWaddr 08:00:27:B6:17:22
inet addr:192.168.196.73 Bcast:192.168.199.255 Mask:255.255.248.0
inet6 addr: fe80::a00:27ff:feb6:1722/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:53473 errors:0 dropped:0 overruns:0 frame:0
TX packets:548 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3543072 (3.3 MiB) TX bytes:72052 (70.3 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[halcyon@192.168.196.73 ~]$ ls
[halcyon@192.168.196.73 ~]$ pwd
/home/halcyon
[halcyon@192.168.196.73 ~]$ ifconfig
eth0 Link encap:Ethernet HWaddr 08:00:27:AE:97:4F
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feae:974f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:616 errors:0 dropped:0 overruns:0 frame:0
TX packets:431 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:63001 (61.5 KiB) TX bytes:53086 (51.8 KiB)
eth1 Link encap:Ethernet HWaddr 08:00:27:B6:17:22
inet addr:192.168.196.73 Bcast:192.168.199.255 Mask:255.255.248.0
inet6 addr: fe80::a00:27ff:feb6:1722/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:54022 errors:0 dropped:0 overruns:0 frame:0
TX packets:560 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3583036 (3.4 MiB) TX bytes:73616 (71.8 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[halcyon@192.168.196.73 ~]$ ifconfig
eth0 Link encap:Ethernet HWaddr 08:00:27:AE:97:4F
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feae:974f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:616 errors:0 dropped:0 overruns:0 frame:0
TX packets:431 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:63001 (61.5 KiB) TX bytes:53086 (51.8 KiB)
eth1 Link encap:Ethernet HWaddr 08:00:27:B6:17:22
inet addr:192.168.196.73 Bcast:192.168.199.255 Mask:255.255.248.0
inet6 addr: fe80::a00:27ff:feb6:1722/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:54145 errors:0 dropped:0 overruns:0 frame:0
TX packets:569 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3593530 (3.4 MiB) TX bytes:74598 (72.8 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ pwd
/home/halcyon
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ ifconfig
eth0 Link encap:Ethernet HWaddr 08:00:27:AE:97:4F
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feae:974f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:616 errors:0 dropped:0 overruns:0 frame:0
TX packets:431 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:63001 (61.5 KiB) TX bytes:53086 (51.8 KiB)
eth1 Link encap:Ethernet HWaddr 08:00:27:B6:17:22
inet addr:192.168.196.73 Bcast:192.168.199.255 Mask:255.255.248.0
inet6 addr: fe80::a00:27ff:feb6:1722/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:63814 errors:0 dropped:0 overruns:0 frame:0
TX packets:609 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:4187378 (3.9 MiB) TX bytes:78400 (76.5 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[halcyon@192.168.196.73 ~]$ ll
total 0
[halcyon@192.168.196.73 ~]$ ifconfgiig
eth0 Link encap:Ethernet HWaddr 08:00:27:AE:97:4F
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feae:974f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:616 errors:0 dropped:0 overruns:0 frame:0
TX packets:431 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:63001 (61.5 KiB) TX bytes:53086 (51.8 KiB)
eth1 Link encap:Ethernet HWaddr 08:00:27:B6:17:22
inet addr:192.168.196.73 Bcast:192.168.199.255 Mask:255.255.248.0
inet6 addr: fe80::a00:27ff:feb6:1722/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:64147 errors:0 dropped:0 overruns:0 frame:0
TX packets:631 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:4208452 (4.0 MiB) TX bytes:80576 (78.6 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[halcyon@192.168.196.73 ~]$
\ No newline at end of file
PS1='[\u@192.168.199.158 \W]\$ '
Last login: Sat Jan 24 08:06:24 2015 from 192.168.192.84
clear;echo -e '\033[32mLogin 192.168.199.158 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.199.158 \W]\$ '
[halcyon@192.168.199.158 ~]$ clear;echo -e '\033[32mLogin 192.168.199.158 done. Enjoy it.\033[0m'
Login 192.168.199.158 done. Enjoy it.
[halcyon@192.168.199.158 ~]$ ll
total 0
[halcyon@192.168.199.158 ~]$ ll
total 0
[halcyon@192.168.199.158 ~]$ ifconfig
eth0 Link encap:Ethernet HWaddr 08:00:27:AE:97:4F
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feae:974f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:584 errors:0 dropped:0 overruns:0 frame:0
TX packets:384 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:61072 (59.6 KiB) TX bytes:50796 (49.6 KiB)
eth1 Link encap:Ethernet HWaddr 08:00:27:B6:17:22
inet addr:192.168.199.158 Bcast:192.168.199.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feb6:1722/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:629 errors:0 dropped:0 overruns:0 frame:0
TX packets:67 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:41737 (40.7 KiB) TX bytes:8573 (8.3 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
[halcyon@192.168.199.158 ~]$ [halcyon@192.168.199.158 ~]$ python
Python 2.6.6 (r266:84292, Nov 22 2013, 12:11:10)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.systemkill()1)1)1)1)1),) )9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 3] No such process
>>>
\ No newline at end of file
PS1='[\u@192.168.199.158 \W]\$ '
Last login: Sun Jan 25 08:43:07 2015 from 192.168.199.162
clear;echo -e '\033[32mLogin 192.168.199.158 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.199.158 \W]\$ '
[halcyon@192.168.199.158 ~]$ clear;echo -e '\033[32mLogin 192.168.199.158 done. Enjoy it.\033[0m'
Login 192.168.199.158 done. Enjoy it.
[halcyon@192.168.199.158 ~]$ ll
total 0
[halcyon@192.168.199.158 ~]$
\ No newline at end of file
PS1='[\u@192.168.199.158 \W]\$ '
Last login: Sun Jan 25 09:46:01 2015 from 192.168.199.162
clear;echo -e '\033[32mLogin 192.168.199.158 done. Enjoy it.\033[0m'
[halcyon@localhost ~]$ PS1='[\u@192.168.199.158 \W]\$ '
[halcyon@192.168.199.158 ~]$ clear;echo -e '\033[32mLogin 192.168.199.158 done. Enjoy it.\033[0m'
Login 192.168.199.158 done. Enjoy it.
[halcyon@192.168.199.158 ~]$ ll
total 0
[halcyon@192.168.199.158 ~]$
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
......@@ -60,7 +60,7 @@
{{ group }}
{% endfor %}
</td>
<td class="text-center"> {{ post.date_added }} </td>
<td class="text-center"> {{ post.date_added|date:"Y-m-d H:i:s" }} </td>
<td class="text-center"> {{ post.comment }} </td>
<td class="text-center">
<a href="/jasset/{{ post.ip }}/" class="iframe btn btn-xs btn-primary">详情</a>
......
{% extends 'base.html' %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<style>
.modal-dialog {
width: 800px;
}
.modal-body {
background-color: #000000;
}
</style>
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="panel-heading">
<div class="panel-title m-b-md"><h4> 用户日志详细信息列表 </h4></div>
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" href="#tab-1"><i class="fa fa-laptop"></i> 在线 </a></li>
<li class=""><a data-toggle="tab" href="#tab-2"><i class="fa fa-bar-chart-o"></i> 历史记录 </a></li>
</ul>
</div>
</div>
<div class="panel-body">
<div class="tab-content">
<div id="tab-1" class="ibox float-e-margins tab-pane active">
<div class="ibox-content">
<table class="table table-striped table-bordered table-hover " id="editable" >
<thead>
<tr>
<th class="text-center"> 用户名 </th>
<th class="text-center"> 登录主机 </th>
<th class="text-center"> 实时监控 </th>
<th class="text-center"> 阻断 </th>
<th class="text-center"> 登录时间 </th>
<th class="text-center"> 结束时间 </th>
</tr>
</thead>
<tbody>
{% for post in online %}
<tr class="gradeX">
<td class="text-center"> {{ post.user.name }} </td>
<td class="text-center"> {{ post.asset.ip }} </td>
<td class="text-center"><a class="monitor" filename="{{ post.log_path }}"> 监控 </a></td>
<td class="text-center"><a href="/jlog/log_kill/{{ post.pid }}"> 阻断 </a></td>
<td class="text-center"> {{ post.start_time|date:"Y-m-d H:i:s" }} </td>
<td class="text-center"> {{ post.end_time|date:"Y-m-d H:i:s" }} </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div id="tab-2" class="ibox float-e-margins tab-pane">
<div class="ibox-content">
<table class="table table-striped table-bordered table-hover " id="editable" >
<thead>
<tr>
<th class="text-center"> 用户名 </th>
<th class="text-center"> 登录主机 </th>
<th class="text-center"> 命令统计 </th>
<th class="text-center"> 登录时间 </th>
<th class="text-center"> 结束时间 </th>
</tr>
</thead>
<tbody>
{% for post in offline %}
<tr class="gradeX">
<td class="text-center"> {{ post.user.name }} </td>
<td class="text-center"> {{ post.asset.ip }} </td>
<td class="text-center"> 命令统计 </td>
<td class="text-center"> {{ post.start_time|date:"Y-m-d H:i:s"}} </td>
<td class="text-center"> {{ post.end_time|date:"Y-m-d H:i:s" }} </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div id="tab-2" class="tab-pane">
<p>This is tab-2</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="http://{{ web_socket_host }}/socket.io/socket.io.js"></script>
<script>
$.fn.webSocket = function(opt){
var st = {};
st = $.extend(st,opt);
var message = {};
var $this = $(this);
var genUid = function(){
return new Date().getTime()+""+Math.floor(Math.random()*899+100);
};
var init = function(e){
var socket = io.connect('ws://'+globalConfig.SOCKET_HOST);
var node = $(e.target);
message.id = genUid();
message.filename = node.attr('filename');
BootstrapDialog.show({message:function(){
var escapeString = function (html){
var elem = document.createElement('div')
var txt = document.createTextNode(html)
elem.appendChild(txt)
return elem.innerHTML;
}
var tag = $('<div id="log" style="height: 500px;overflow: auto;"></div>');
//告诉服务器端有用户登录
socket.emit('login', {userid:message.id, filename:message.filename});
socket.on('message',function(obj){
//去除log中的颜色控制字符
var regx = /\x1B\[([0-9]{1,3}((;[0-9]{1,3})*)?)?[m|K]/g;
// tag.append('<p>'+escapeString(obj.content.replace(regx,''))+'</p>');
tag.append('<p>'+escapeString(obj.content)+'</p>');
tag.animate({ scrollTop: tag[0].scrollHeight}, 1);
});
tag[0].style.color = "#00FF00";
return tag[0];
} ,
title:'Jumpserver实时监控:',
onhide:function(){
socket.emit('disconnect');
}});
}
$this.on("click",function(e){
init(e);
return false;
});
}
$('.log_command').on('click',function(){
var url = $(this).attr('href');
$.ajax({url:url,success:function(data){
BootstrapDialog.show({title:'命令统计',message:data});
}});
return false;
})
globalConfig = {
SOCKET_HOST: "{{ web_socket_host }}"
}
$(".monitor").webSocket()
</script>
{% endblock %}
\ No newline at end of file
......@@ -34,17 +34,23 @@
{% if msg %}
<div class="alert alert-success text-center">{{ msg }}</div>
{% endif %}
<div class="form-group hidden">
<label for="group_id" class="col-sm-2 control-label">ID<span class="red-fonts">*</span></label>
<div class="col-sm-8">
<input id="group_id" name="group_id" placeholder="Group name" type="text" class="form-control" value="{{ group_id }}">
</div>
</div>
<div class="form-group">
<label for="group_name" class="col-sm-2 control-label">组名<span class="red-fonts">*</span></label>
<div class="col-sm-8">
<input id="group_name" name="group_name" placeholder="Group name" type="text" class="form-control">
<input id="group_name" name="group_name" placeholder="Group name" type="text" class="form-control" value="{{ group_name }}">
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label for="comment" class="col-sm-2 control-label">备注</label>
<div class="col-sm-8">
<input id="comment" name="comment" placeholder="Comment" type="text" class="form-control">
<input id="comment" name="comment" placeholder="Comment" type="text" class="form-control" value="{{ comment }}">
</div>
</div>
......
{% load mytags %}
<html>
<head>
{% include 'link_css.html' %}
<style type="text/css">
body
{
background: #FFFFFF;
}
</style>
</head>
<body>
<div class="row">
<div class="contact-box">
<h2 class="text-center">{{ group.name }} 属组详情</h2>
<div class="ibox-content">
<table class="table table-striped table-bordered table-hover " id="editable" >
<thead>
<tr>
<th class="text-center">属组</th>
<th class="text-center">详情</th>
</tr>
</thead>
<tbody>
<tr class="gradeX">
<td class="text-center">ID</td>
<td class="text-center">{{ group.id }}</td>
</tr>
<tr class="gradeX">
<td class="text-center">组名</td>
<td class="text-center">{{ group.name }}</td>
</tr>
<tr class="gradeX">
<td class="text-center">备注</td>
<td class="text-center">{{ group_comment }}</td>
</tr>
</table>
</div>
</div>
</body>
</html>
\ No newline at end of file
{% extends 'base.html' %}
{% load mytags %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>属组信息 <small> show group info.</small></h5>
<h5> 查看分组 <small> show group info.</small> </h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
......@@ -26,46 +27,86 @@
</a>
</div>
</div>
<div class="ibox-content" style="display: block;">
<form method="post" action="">
<table class="table table-hover">
<div class="ibox-content">
<div class="">
<a target="_blank" href="/juser/group_add/" class="btn btn-sm btn-primary "> 添加 </a>
</div>
<table class="table table-striped table-bordered table-hover " id="editable" >
<thead>
<tr>
<th>
<div class="checkbox i-checks">
<input onclick="selectAll()" type="checkbox" name="select_all" style="select_all" id="select_all">
</div>
</th>
<th>ID</th>
<th>组名</th>
<th>备注</th>
<th class="text-center"><input type="checkbox" class="i-checks" name=""></th>
<th class="text-center">ID</th>
<th class="text-center">组名</th>
<th class="text-center">备注</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{% for group in groups %}
<tr>
<td>
<div class="checkbox i-checks">
<input type="checkbox" value="{{ group.id }}" name="selected">
</div>
{% for group in contacts.object_list %}
<tr class="gradeX">
<td class="text-center"><input type="checkbox" class="i-checks" name=""></td>
<td class="text-center"> {{ group.id }} </td>
<td class="text-center"> {{ group.name }} </td>
<td class="text-center"> {{ group.comment }} </td>
<td class="text-center">
<a href="../group_detail/?id={{ group.id }}" class="iframe btn btn-xs btn-primary">详情</a>
<a href="../group_edit/?id={{ group.id }}" class="btn btn-xs btn-info">编辑</a>
<a href="../group_del/?id={{ group.id }}" class="btn btn-xs btn-danger">删除</a>
</td>
<td>{{ group.id }}</td>
<td>{{ group.name }}</td>
<td>{{ group.comment }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="submit">取消</button>
<button id="submit_button" class="btn btn-primary" type="submit">确认删除</button>
<div class="row">
<div class="col-sm-6">
<div class="dataTables_info" id="editable_info" role="status" aria-live="polite">
Showing {{ contacts.start_index }} to {{ contacts.end_index }} of {{ p.count }} entries
</div>
</div>
</form>
<div class="col-sm-6">
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
<ul class="pagination" style="margin-top: 0; float: right">
{% if contacts.has_previous %}
<li class="paginate_button previous" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="?page={{ contacts.previous_page_number }}">Previous</a>
</li>
{% else %}
<li class="paginate_button previous disabled" aria-controls="editable" tabindex="0" id="editable_previous">
<a href="#">Previous</a>
</li>
{% endif %}
{% for page in p.page_range %}
{% ifequal offset1 page %}
<li class="paginate_button active" aria-controls="editable" tabindex="0"><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li class="paginate_button" aria-controls="editable" tabindex="0"><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% if contacts.has_next %}
<li class="paginate_button next" aria-controls="editable" tabindex="0" id="editable_next">
<a href="?page={{ contacts.next_page_number }}">Next</a>
</li>
{% else %}
<li class="paginate_button next disabled" aria-controls="editable" tabindex="0" id="editable_next">
<a href="#">Next</a>
</li>
{% endif %}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$(".iframe").colorbox({iframe:true, width:"70%", height:"70%"});
});
</script>
{% endblock %}
\ No newline at end of file
......@@ -35,10 +35,10 @@
{% if msg %}
<div class="alert alert-success text-center">{{ msg }}</div>
{% endif %}
<div class="form-group {{ hidden }}">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名<span class="red-fonts">*</span></label>
<div class="col-sm-8">
<input id="username" name="username" placeholder="Username" type="text" class="form-control" value={{ username }}>
<input id="username" name="username" placeholder="Username" type="text" class="form-control" value={{ username }} {{ readonly }}>
</div>
</div>
<div class="hr-line-dashed"></div>
......
......@@ -59,9 +59,9 @@
<td class="text-center">{{ user.email }}</td>
<td class="text-center">{{ user.is_active|bool2str }}</td>
<td class="text-center">
<a href="../user_detail/?username={{ user.username }}" class="iframe btn btn-xs btn-primary">详情</a>
<a href="../user_edit/?username={{ user.username }}" class="btn btn-xs btn-info">编辑</a>
<a href="../user_del/?username={{ user.username }}" class="btn btn-xs btn-danger">删除</a>
<a href="../user_detail/?id={{ user.id }}" class="iframe btn btn-xs btn-primary">详情</a>
<a href="../user_edit/?id={{ user.id }}" class="btn btn-xs btn-info">编辑</a>
<a href="../user_del/?id={{ user.id }}" class="btn btn-xs btn-danger">删除</a>
</td>
</tr>
{% endfor %}
......
{% extends 'base.html' %}
{% load mytags %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-10">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>用户信息 <small> show user info.</small></h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content" style="display: block;">
<form method="post" action="">
<table class="table table-hover">
<thead>
<tr>
<th>
<div class="checkbox i-checks">
<input onclick="selectAll()" type="checkbox" name="select_all" style="select_all" id="select_all">
</div>
</th>
<th>ID</th>
<th>用户名</th>
<th>姓名</th>
<th>属组</th>
<th>角色</th>
<th>Email</th>
<th>激活</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>
<div class="checkbox i-checks">
<input type="checkbox" value="{{ user.id }}" name="selected">
</div>
</td>
<td>{{ user.id }}</td>
<td>{{ user.username }}</td>
<td>{{ user.name }}</td>
<td>{{ user.username|groups_str }}</td>
<td>{{ user.id|get_role }}</td>
<td>{{ user.email }}</td>
<td>{{ user.is_active }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="submit">取消</button>
<button id="submit_button" class="btn btn-primary" type="submit">确认删除</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
\ No newline at end of file
......@@ -3,6 +3,7 @@
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/plugins/metisMenu/jquery.metisMenu.js"></script>
<script src="/static/js/plugins/slimscroll/jquery.slimscroll.min.js"></script>
<script src="/static/js/bootstrap-dialog.js"></script>
<!-- Peity -->
<script src="/static/js/plugins/peity/jquery.peity.min.js"></script>
......
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var spawn = require('child_process').spawn;
var Tail = require('tail').Tail;
app.get('/', function(req, res){
res.send('<h1>Welcome Realtime Server</h1>');
});
//在线用户
var onlineUsers = {};
//当前在线人数
var onlineCount = 0;
io.on('connection', function(socket){
//console.log('a user connected');
//监听新用户加入
socket.on('login', function(obj){
//将新加入用户的唯一标识当作socket的名称,后面退出的时候会用到
socket.name = obj.userid;
socket.fileName = obj.filename;
var tail = new Tail(obj.filename);
//console.log(obj.filename);
tail.on('line',function(data) {
//console.log(data);
var newData = {userid:obj.userid,username:obj.username,content:data};
socket.emit('message',newData);
});
// var tail = spawn("tail", ['-f', obj.filename]);
// tail.stdout.on('data',function(data){
// var content = data.toString();
// //console.log(content);
// var newData = {userid:obj.userid,username:obj.username,content:content};
// socket.emit('message',newData);
// });
socket.tail = tail;
//检查在线列表,如果不在里面就加入
if(!onlineUsers.hasOwnProperty(obj.userid)) {
onlineUsers[obj.userid] = obj.username;
//在线人数+1
onlineCount++;
}
//向所有客户端广播用户加入
//io.emit('login', {onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});
//console.log(obj.username+'加入了聊天室');
});
//监听用户退出
socket.on('disconnect', function(){
//将退出的用户从在线列表中删除
if(onlineUsers.hasOwnProperty(socket.name)) {
//退出用户的信息
var obj = {userid:socket.name, username:onlineUsers[socket.name]};
if( socket.tail){
socket.tail.unwatch();
}
//删除
delete onlineUsers[socket.name];
//在线人数-1
onlineCount--;
//向所有客户端广播用户退出
//io.emit('logout', {onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});
////console.log(obj.username+'退出了聊天室');
}
});
//监听用户发布聊天内容
socket.on('message', function(obj){
//向所有客户端广播发布的消息
//io.emit('message', obj);
socket.emit('message',obj);
////console.log(obj.username+'说:'+obj.content);
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
../node-tail/bin/node-tail
\ No newline at end of file
This diff is collapsed.
(The MIT License)
Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/)
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
```js
var express = require('express')
var app = express()
app.get('/', function (req, res) {
res.send('Hello World')
})
app.listen(3000)
```
## Installation
```bash
$ npm install express
```
## Features
* Robust routing
* Focus on high performance
* Super-high test coverage
* HTTP helpers (redirection, caching, etc)
* View system supporting 14+ template engines
* Content negotiation
* Executable for generating applications quickly
## Docs & Community
* [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/strongloop/expressjs.com)]
* [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
* [Github Organization](https://github.com/expressjs) for Official Middleware & Modules
* Visit the [Wiki](https://github.com/strongloop/express/wiki)
* [Google Group](https://groups.google.com/group/express-js) for discussion
* [Русскоязычная документация](http://jsman.ru/express/)
* [한국어 문서](http://expressjs.kr) - [[website repo](https://github.com/Hanul/expressjs.kr)]
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/strongloop/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/strongloop/express/wiki/New-features-in-4.x).
## Quick Start
The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:
Install the executable. The executable's major version will match Express's:
```bash
$ npm install -g express-generator@4
```
Create the app:
```bash
$ express /tmp/foo && cd /tmp/foo
```
Install dependencies:
```bash
$ npm install
```
Start the server:
```bash
$ npm start
```
## Philosophy
The Express philosophy is to provide small, robust tooling for HTTP servers, making
it a great solution for single page applications, web sites, hybrids, or public
HTTP APIs.
Express does not force you to use any specific ORM or template engine. With support for over
14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),
you can quickly craft your perfect framework.
## Examples
To view the examples, clone the Express repo and install the dependancies:
```bash
$ git clone git://github.com/strongloop/express.git --depth 1
$ cd express
$ npm install
```
Then run whichever example you want:
```bash
$ node examples/content-negotiation
```
## Tests
To run the test suite, first install the dependancies, then run `npm test`:
```bash
$ npm install
$ npm test
```
## People
The original author of Express is [TJ Holowaychuk](https://github.com/tj) [![TJ's Gratipay][gratipay-image-visionmedia]][gratipay-url-visionmedia]
The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [![Doug's Gratipay][gratipay-image-dougwilson]][gratipay-url-dougwilson]
[List of all contributors](https://github.com/strongloop/express/graphs/contributors)
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/express.svg?style=flat
[npm-url]: https://npmjs.org/package/express
[downloads-image]: https://img.shields.io/npm/dm/express.svg?style=flat
[downloads-url]: https://npmjs.org/package/express
[travis-image]: https://img.shields.io/travis/strongloop/express.svg?style=flat
[travis-url]: https://travis-ci.org/strongloop/express
[coveralls-image]: https://img.shields.io/coveralls/strongloop/express.svg?style=flat
[coveralls-url]: https://coveralls.io/r/strongloop/express?branch=master
[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg?style=flat
[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/
[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg?style=flat
[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/
module.exports = require('./lib/express');
1.1.4 / 2014-12-10
==================
* deps: mime-types@~2.0.4
- deps: mime-db@~1.3.0
1.1.3 / 2014-11-09
==================
* deps: mime-types@~2.0.3
- deps: mime-db@~1.2.0
1.1.2 / 2014-10-14
==================
* deps: negotiator@0.4.9
- Fix error when media type has invalid parameter
1.1.1 / 2014-09-28
==================
* deps: mime-types@~2.0.2
- deps: mime-db@~1.1.0
* deps: negotiator@0.4.8
- Fix all negotiations to be case-insensitive
- Stable sort preferences of same quality according to client order
1.1.0 / 2014-09-02
==================
* update `mime-types`
1.0.7 / 2014-07-04
==================
* Fix wrong type returned from `type` when match after unknown extension
1.0.6 / 2014-06-24
==================
* deps: negotiator@0.4.7
1.0.5 / 2014-06-20
==================
* fix crash when unknown extension given
1.0.4 / 2014-06-19
==================
* use `mime-types`
1.0.3 / 2014-06-11
==================
* deps: negotiator@0.4.6
- Order by specificity when quality is the same
1.0.2 / 2014-05-29
==================
* Fix interpretation when header not in request
* deps: pin negotiator@0.4.5
1.0.1 / 2014-01-18
==================
* Identity encoding isn't always acceptable
* deps: negotiator@~0.4.0
1.0.0 / 2013-12-27
==================
* Genesis
(The MIT License)
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# accepts
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Higher level content negotation based on [negotiator](https://github.com/federomero/negotiator). Extracted from [koa](https://github.com/koajs/koa) for general use.
In addition to negotatior, it allows:
- Allows types as an array or arguments list, ie `(['text/html', 'application/json'])` as well as `('text/html', 'application/json')`.
- Allows type shorthands such as `json`.
- Returns `false` when no types match
- Treats non-existent headers as `*`
## API
### var accept = new Accepts(req)
```js
var accepts = require('accepts')
http.createServer(function (req, res) {
var accept = accepts(req)
})
```
### accept\[property\]\(\)
Returns all the explicitly accepted content property as an array in descending priority.
- `accept.types()`
- `accept.encodings()`
- `accept.charsets()`
- `accept.languages()`
They are also aliased in singular form such as `accept.type()`. `accept.languages()` is also aliased as `accept.langs()`, etc.
Note: you should almost never do this in a real app as it defeats the purpose of content negotiation.
Example:
```js
// in Google Chrome
var encodings = accept.encodings() // -> ['sdch', 'gzip', 'deflate']
```
Since you probably don't support `sdch`, you should just supply the encodings you support:
```js
var encoding = accept.encodings('gzip', 'deflate') // -> 'gzip', probably
```
### accept\[property\]\(values, ...\)
You can either have `values` be an array or have an argument list of values.
If the client does not accept any `values`, `false` will be returned.
If the client accepts any `values`, the preferred `value` will be return.
For `accept.types()`, shorthand mime types are allowed.
Example:
```js
// req.headers.accept = 'application/json'
accept.types('json') // -> 'json'
accept.types('html', 'json') // -> 'json'
accept.types('html') // -> false
// req.headers.accept = ''
// which is equivalent to `*`
accept.types() // -> [], no explicit types
accept.types('text/html', 'text/json') // -> 'text/html', since it was first
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/accepts.svg?style=flat
[npm-url]: https://npmjs.org/package/accepts
[node-version-image]: https://img.shields.io/node/v/accepts.svg?style=flat
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/accepts.svg?style=flat
[travis-url]: https://travis-ci.org/jshttp/accepts
[coveralls-image]: https://img.shields.io/coveralls/jshttp/accepts.svg?style=flat
[coveralls-url]: https://coveralls.io/r/jshttp/accepts
[downloads-image]: https://img.shields.io/npm/dm/accepts.svg?style=flat
[downloads-url]: https://npmjs.org/package/accepts
var Negotiator = require('negotiator')
var mime = require('mime-types')
var slice = [].slice
module.exports = Accepts
function Accepts(req) {
if (!(this instanceof Accepts))
return new Accepts(req)
this.headers = req.headers
this.negotiator = Negotiator(req)
}
/**
* Check if the given `type(s)` is acceptable, returning
* the best match when true, otherwise `undefined`, in which
* case you should respond with 406 "Not Acceptable".
*
* The `type` value may be a single mime type string
* such as "application/json", the extension name
* such as "json" or an array `["json", "html", "text/plain"]`. When a list
* or array is given the _best_ match, if any is returned.
*
* Examples:
*
* // Accept: text/html
* this.types('html');
* // => "html"
*
* // Accept: text/*, application/json
* this.types('html');
* // => "html"
* this.types('text/html');
* // => "text/html"
* this.types('json', 'text');
* // => "json"
* this.types('application/json');
* // => "application/json"
*
* // Accept: text/*, application/json
* this.types('image/png');
* this.types('png');
* // => undefined
*
* // Accept: text/*;q=.5, application/json
* this.types(['html', 'json']);
* this.types('html', 'json');
* // => "json"
*
* @param {String|Array} type(s)...
* @return {String|Array|Boolean}
* @api public
*/
Accepts.prototype.type =
Accepts.prototype.types = function (types) {
if (!Array.isArray(types)) types = slice.call(arguments);
var n = this.negotiator;
if (!types.length) return n.mediaTypes();
if (!this.headers.accept) return types[0];
var mimes = types.map(extToMime);
var accepts = n.mediaTypes(mimes.filter(validMime));
var first = accepts[0];
if (!first) return false;
return types[mimes.indexOf(first)];
}
/**
* Return accepted encodings or best fit based on `encodings`.
*
* Given `Accept-Encoding: gzip, deflate`
* an array sorted by quality is returned:
*
* ['gzip', 'deflate']
*
* @param {String|Array} encoding(s)...
* @return {String|Array}
* @api public
*/
Accepts.prototype.encoding =
Accepts.prototype.encodings = function (encodings) {
if (!Array.isArray(encodings)) encodings = slice.call(arguments);
var n = this.negotiator;
if (!encodings.length) return n.encodings();
return n.encodings(encodings)[0] || false;
}
/**
* Return accepted charsets or best fit based on `charsets`.
*
* Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
* an array sorted by quality is returned:
*
* ['utf-8', 'utf-7', 'iso-8859-1']
*
* @param {String|Array} charset(s)...
* @return {String|Array}
* @api public
*/
Accepts.prototype.charset =
Accepts.prototype.charsets = function (charsets) {
if (!Array.isArray(charsets)) charsets = [].slice.call(arguments);
var n = this.negotiator;
if (!charsets.length) return n.charsets();
if (!this.headers['accept-charset']) return charsets[0];
return n.charsets(charsets)[0] || false;
}
/**
* Return accepted languages or best fit based on `langs`.
*
* Given `Accept-Language: en;q=0.8, es, pt`
* an array sorted by quality is returned:
*
* ['es', 'pt', 'en']
*
* @param {String|Array} lang(s)...
* @return {Array|String}
* @api public
*/
Accepts.prototype.lang =
Accepts.prototype.langs =
Accepts.prototype.language =
Accepts.prototype.languages = function (langs) {
if (!Array.isArray(langs)) langs = slice.call(arguments);
var n = this.negotiator;
if (!langs.length) return n.languages();
if (!this.headers['accept-language']) return langs[0];
return n.languages(langs)[0] || false;
}
/**
* Convert extnames to mime.
*
* @param {String} type
* @return {String}
* @api private
*/
function extToMime(type) {
if (~type.indexOf('/')) return type;
return mime.lookup(type);
}
/**
* Check if mime is valid.
*
* @param {String} type
* @return {String}
* @api private
*/
function validMime(type) {
return typeof type === 'string';
}
2.0.7 / 2014-12-30
==================
* deps: mime-db@~1.5.0
- Add new mime types
- Fix various invalid MIME type entries
2.0.6 / 2014-12-30
==================
* deps: mime-db@~1.4.0
- Add new mime types
- Fix various invalid MIME type entries
- Remove example template MIME types
2.0.5 / 2014-12-29
==================
* deps: mime-db@~1.3.1
- Fix missing extensions
2.0.4 / 2014-12-10
==================
* deps: mime-db@~1.3.0
- Add new mime types
2.0.3 / 2014-11-09
==================
* deps: mime-db@~1.2.0
- Add new mime types
2.0.2 / 2014-09-28
==================
* deps: mime-db@~1.1.0
- Add new mime types
- Add additional compressible
- Update charsets
2.0.1 / 2014-09-07
==================
* Support Node.js 0.6
2.0.0 / 2014-09-02
==================
* Use `mime-db`
* Remove `.define()`
1.0.2 / 2014-08-04
==================
* Set charset=utf-8 for `text/javascript`
1.0.1 / 2014-06-24
==================
* Add `text/jsx` type
1.0.0 / 2014-05-12
==================
* Return `false` for unknown types
* Set charset=utf-8 for `application/json`
0.1.0 / 2014-05-02
==================
* Initial release
The MIT License (MIT)
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# mime-types
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
The ultimate javascript content-type utility.
Similar to [node-mime](https://github.com/broofa/node-mime), except:
- __No fallbacks.__ Instead of naively returning the first available type, `mime-types` simply returns `false`,
so do `var type = mime.lookup('unrecognized') || 'application/octet-stream'`.
- No `new Mime()` business, so you could do `var lookup = require('mime-types').lookup`.
- Additional mime types are added such as jade and stylus via [mime-db](https://github.com/jshttp/mime-db)
- No `.define()` functionality
Otherwise, the API is compatible.
## Install
```sh
$ npm install mime-types
```
## Adding Types
All mime types are based on [mime-db](https://github.com/jshttp/mime-db),
so open a PR there if you'd like to add mime types.
## API
```js
var mime = require('mime-types')
```
All functions return `false` if input is invalid or not found.
### mime.lookup(path)
Lookup the content-type associated with a file.
```js
mime.lookup('json') // 'application/json'
mime.lookup('.md') // 'text/x-markdown'
mime.lookup('file.html') // 'text/html'
mime.lookup('folder/file.js') // 'application/javascript'
mime.lookup('cats') // false
```
### mime.contentType(type)
Create a full content-type header given a content-type or extension.
```js
mime.contentType('markdown') // 'text/x-markdown; charset=utf-8'
mime.contentType('file.json') // 'application/json; charset=utf-8'
```
### mime.extension(type)
Get the default extension for a content-type.
```js
mime.extension('application/octet-stream') // 'bin'
```
### mime.charset(type)
Lookup the implied default charset of a content-type.
```js
mime.charset('text/x-markdown') // 'UTF-8'
```
### var type = mime.types[extension]
A map of content-types by extension.
### [extensions...] = mime.extensions[type]
A map of extensions by content-type.
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/mime-types.svg?style=flat
[npm-url]: https://npmjs.org/package/mime-types
[node-version-image]: https://img.shields.io/badge/node.js-%3E%3D_0.6-brightgreen.svg?style=flat
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/mime-types.svg?style=flat
[travis-url]: https://travis-ci.org/jshttp/mime-types
[coveralls-image]: https://img.shields.io/coveralls/jshttp/mime-types.svg?style=flat
[coveralls-url]: https://coveralls.io/r/jshttp/mime-types
[downloads-image]: https://img.shields.io/npm/dm/mime-types.svg?style=flat
[downloads-url]: https://npmjs.org/package/mime-types
var db = require('mime-db')
// types[extension] = type
exports.types = Object.create(null)
// extensions[type] = [extensions]
exports.extensions = Object.create(null)
Object.keys(db).forEach(function (name) {
var mime = db[name]
var exts = mime.extensions
if (!exts || !exts.length) return
exports.extensions[name] = exts
exts.forEach(function (ext) {
exports.types[ext] = name
})
})
exports.lookup = function (string) {
if (!string || typeof string !== "string") return false
// remove any leading paths, though we should just use path.basename
string = string.replace(/.*[\.\/\\]/, '').toLowerCase()
if (!string) return false
return exports.types[string] || false
}
exports.extension = function (type) {
if (!type || typeof type !== "string") return false
// to do: use media-typer
type = type.match(/^\s*([^;\s]*)(?:;|\s|$)/)
if (!type) return false
var exts = exports.extensions[type[1].toLowerCase()]
if (!exts || !exts.length) return false
return exts[0]
}
// type has to be an exact mime type
exports.charset = function (type) {
var mime = db[type]
if (mime && mime.charset) return mime.charset
// default text/* to utf-8
if (/^text\//.test(type)) return 'UTF-8'
return false
}
// backwards compatibility
exports.charsets = {
lookup: exports.charset
}
// to do: maybe use set-type module or something
exports.contentType = function (type) {
if (!type || typeof type !== "string") return false
if (!~type.indexOf('/')) type = exports.lookup(type)
if (!type) return false
if (!~type.indexOf('charset')) {
var charset = exports.charset(type)
if (charset) type += '; charset=' + charset.toLowerCase()
}
return type
}
1.5.0 / 2014-12-30
==================
* Add `application/vnd.oracle.resource+json`
* Fix various invalid MIME type entries
- `application/mbox+xml`
- `application/oscp-response`
- `application/vwg-multiplexed`
- `audio/g721`
1.4.0 / 2014-12-21
==================
* Add `application/vnd.ims.imsccv1p2`
* Fix various invalid MIME type entries
- `application/vnd-acucobol`
- `application/vnd-curl`
- `application/vnd-dart`
- `application/vnd-dxr`
- `application/vnd-fdf`
- `application/vnd-mif`
- `application/vnd-sema`
- `application/vnd-wap-wmlc`
- `application/vnd.adobe.flash-movie`
- `application/vnd.dece-zip`
- `application/vnd.dvb_service`
- `application/vnd.micrografx-igx`
- `application/vnd.sealed-doc`
- `application/vnd.sealed-eml`
- `application/vnd.sealed-mht`
- `application/vnd.sealed-ppt`
- `application/vnd.sealed-tiff`
- `application/vnd.sealed-xls`
- `application/vnd.sealedmedia.softseal-html`
- `application/vnd.sealedmedia.softseal-pdf`
- `application/vnd.wap-slc`
- `application/vnd.wap-wbxml`
- `audio/vnd.sealedmedia.softseal-mpeg`
- `image/vnd-djvu`
- `image/vnd-svf`
- `image/vnd-wap-wbmp`
- `image/vnd.sealed-png`
- `image/vnd.sealedmedia.softseal-gif`
- `image/vnd.sealedmedia.softseal-jpg`
- `model/vnd-dwf`
- `model/vnd.parasolid.transmit-binary`
- `model/vnd.parasolid.transmit-text`
- `text/vnd-a`
- `text/vnd-curl`
- `text/vnd.wap-wml`
* Remove example template MIME types
- `application/example`
- `audio/example`
- `image/example`
- `message/example`
- `model/example`
- `multipart/example`
- `text/example`
- `video/example`
1.3.1 / 2014-12-16
==================
* Fix missing extensions
- `application/json5`
- `text/hjson`
1.3.0 / 2014-12-07
==================
* Add `application/a2l`
* Add `application/aml`
* Add `application/atfx`
* Add `application/atxml`
* Add `application/cdfx+xml`
* Add `application/dii`
* Add `application/json5`
* Add `application/lxf`
* Add `application/mf4`
* Add `application/vnd.apache.thrift.compact`
* Add `application/vnd.apache.thrift.json`
* Add `application/vnd.coffeescript`
* Add `application/vnd.enphase.envoy`
* Add `application/vnd.ims.imsccv1p1`
* Add `text/csv-schema`
* Add `text/hjson`
* Add `text/markdown`
* Add `text/yaml`
1.2.0 / 2014-11-09
==================
* Add `application/cea`
* Add `application/dit`
* Add `application/vnd.gov.sk.e-form+zip`
* Add `application/vnd.tmd.mediaflex.api+xml`
* Type `application/epub+zip` is now IANA-registered
1.1.2 / 2014-10-23
==================
* Rebuild database for `application/x-www-form-urlencoded` change
1.1.1 / 2014-10-20
==================
* Mark `application/x-www-form-urlencoded` as compressible.
1.1.0 / 2014-09-28
==================
* Add `application/font-woff2`
1.0.3 / 2014-09-25
==================
* Fix engine requirement in package
1.0.2 / 2014-09-25
==================
* Add `application/coap-group+json`
* Add `application/dcd`
* Add `application/vnd.apache.thrift.binary`
* Add `image/vnd.tencent.tap`
* Mark all JSON-derived types as compressible
* Update `text/vtt` data
1.0.1 / 2014-08-30
==================
* Fix extension ordering
1.0.0 / 2014-08-30
==================
* Add `application/atf`
* Add `application/merge-patch+json`
* Add `multipart/x-mixed-replace`
* Add `source: 'apache'` metadata
* Add `source: 'iana'` metadata
* Remove badly-assumed charset data
The MIT License (MIT)
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# mime-db
[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-url]
[![Node.js Version][node-image]][node-url]
[![Build Status][travis-image]][travis-url]
[![Coverage Status][coveralls-image]][coveralls-url]
This is a database of all mime types.
It consistents of a single, public JSON file and does not include any logic,
allowing it to remain as unopinionated as possible with an API.
It aggregates data from the following sources:
- http://www.iana.org/assignments/media-types/media-types.xhtml
- http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
## Usage
```bash
npm i mime-db
```
```js
var db = require('mime-db');
// grab data on .js files
var data = db['application/javascript'];
```
If you're crazy enough to use this in the browser,
you can just grab the JSON file:
```
https://cdn.rawgit.com/jshttp/mime-db/master/db.json
```
## Data Structure
The JSON file is a map lookup for lowercased mime types.
Each mime type has the following properties:
- `.source` - where the mime type is defined.
If not set, it's probably a custom media type.
- `apache` - [Apache common media types](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)
- `iana` - [IANA-defined media types](http://www.iana.org/assignments/media-types/media-types.xhtml)
- `.extensions[]` - known extensions associated with this mime type.
- `.compressible` - whether a file of this type is can be gzipped.
- `.charset` - the default charset associated with this type, if any.
If unknown, every property could be `undefined`.
## Repository Structure
- `scripts` - these are scripts to run to build the database
- `src/` - this is a folder of files created from remote sources like Apache and IANA
- `lib/` - this is a folder of our own custom sources and db, which will be merged into `db.json`
- `db.json` - the final built JSON file for end-user usage
## Contributing
To edit the database, only make PRs against files in the `lib/` folder.
To update the build, run `npm run update`.
[npm-version-image]: https://img.shields.io/npm/v/mime-db.svg?style=flat
[npm-downloads-image]: https://img.shields.io/npm/dm/mime-db.svg?style=flat
[npm-url]: https://npmjs.org/package/mime-db
[travis-image]: https://img.shields.io/travis/jshttp/mime-db.svg?style=flat
[travis-url]: https://travis-ci.org/jshttp/mime-db
[coveralls-image]: https://img.shields.io/coveralls/jshttp/mime-db.svg?style=flat
[coveralls-url]: https://coveralls.io/r/jshttp/mime-db?branch=master
[node-image]: https://img.shields.io/node/v/mime-db.svg?style=flat
[node-url]: http://nodejs.org/download/
/*!
* mime-db
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/**
* Module exports.
*/
module.exports = require('./db.json')
{
"name": "mime-db",
"description": "Media Type Database",
"version": "1.5.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
}
],
"license": "MIT",
"keywords": [
"mime",
"db",
"type",
"types",
"database",
"charset",
"charsets"
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/mime-db"
},
"devDependencies": {
"co": "4",
"cogent": "1",
"csv-parse": "0",
"gnode": "0.1.0",
"istanbul": "0.3.5",
"mocha": "~1.21.4",
"raw-body": "~1.3.1",
"stream-to-array": "2"
},
"files": [
"HISTORY.md",
"LICENSE",
"README.md",
"db.json",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"update": "gnode scripts/extensions && gnode scripts/types && node scripts/build",
"clean": "rm src/*",
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
},
"gitHead": "262fafb4a696cae208d6148c6642ee45bce07cb3",
"bugs": {
"url": "https://github.com/jshttp/mime-db/issues"
},
"homepage": "https://github.com/jshttp/mime-db",
"_id": "mime-db@1.5.0",
"_shasum": "bd80b576157991c3b46c71be7041fc6d5402a6ee",
"_from": "mime-db@~1.5.0",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "bd80b576157991c3b46c71be7041fc6d5402a6ee",
"tarball": "http://registry.npmjs.org/mime-db/-/mime-db-1.5.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.5.0.tgz",
"readme": "ERROR: No README data found!"
}
{
"name": "mime-types",
"description": "The ultimate javascript content-type utility.",
"version": "2.0.7",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Jeremiah Senkpiel",
"email": "fishrock123@rocketmail.com",
"url": "https://searchbeam.jit.su"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
}
],
"license": "MIT",
"keywords": [
"mime",
"types"
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/mime-types"
},
"dependencies": {
"mime-db": "~1.5.0"
},
"devDependencies": {
"istanbul": "0.3.5",
"mocha": "~1.21.5"
},
"files": [
"HISTORY.md",
"LICENSE",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec test/test.js",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot test/test.js",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter dot test/test.js"
},
"gitHead": "4216c095dcc3390c2b8f4a96a9eae94d11420f56",
"bugs": {
"url": "https://github.com/jshttp/mime-types/issues"
},
"homepage": "https://github.com/jshttp/mime-types",
"_id": "mime-types@2.0.7",
"_shasum": "0cb58d0403aec977357db324eea67e40c32b44b2",
"_from": "mime-types@~2.0.4",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "fishrock123",
"email": "fishrock123@rocketmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "0cb58d0403aec977357db324eea67e40c32b44b2",
"tarball": "http://registry.npmjs.org/mime-types/-/mime-types-2.0.7.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.7.tgz",
"readme": "ERROR: No README data found!"
}
(The MIT License)
Copyright (c) 2012 Federico Romero
Copyright (c) 2012-2014 Isaac Z. Schlueter
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# negotiator
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
An HTTP content negotiator for Node.js
## Installation
```sh
$ npm install negotiator
```
## API
```js
var Negotiator = require('negotiator')
```
### Accept Negotiation
```js
availableMediaTypes = ['text/html', 'text/plain', 'application/json']
// The negotiator constructor receives a request object
negotiator = new Negotiator(request)
// Let's say Accept header is 'text/html, application/*;q=0.2, image/jpeg;q=0.8'
negotiator.mediaTypes()
// -> ['text/html', 'image/jpeg', 'application/*']
negotiator.mediaTypes(availableMediaTypes)
// -> ['text/html', 'application/json']
negotiator.mediaType(availableMediaTypes)
// -> 'text/html'
```
You can check a working example at `examples/accept.js`.
#### Methods
##### mediaTypes(availableMediaTypes):
Returns an array of preferred media types ordered by priority from a list of available media types.
##### mediaType(availableMediaType):
Returns the top preferred media type from a list of available media types.
### Accept-Language Negotiation
```js
negotiator = new Negotiator(request)
availableLanguages = 'en', 'es', 'fr'
// Let's say Accept-Language header is 'en;q=0.8, es, pt'
negotiator.languages()
// -> ['es', 'pt', 'en']
negotiator.languages(availableLanguages)
// -> ['es', 'en']
language = negotiator.language(availableLanguages)
// -> 'es'
```
You can check a working example at `examples/language.js`.
#### Methods
##### languages(availableLanguages):
Returns an array of preferred languages ordered by priority from a list of available languages.
##### language(availableLanguages):
Returns the top preferred language from a list of available languages.
### Accept-Charset Negotiation
```js
availableCharsets = ['utf-8', 'iso-8859-1', 'iso-8859-5']
negotiator = new Negotiator(request)
// Let's say Accept-Charset header is 'utf-8, iso-8859-1;q=0.8, utf-7;q=0.2'
negotiator.charsets()
// -> ['utf-8', 'iso-8859-1', 'utf-7']
negotiator.charsets(availableCharsets)
// -> ['utf-8', 'iso-8859-1']
negotiator.charset(availableCharsets)
// -> 'utf-8'
```
You can check a working example at `examples/charset.js`.
#### Methods
##### charsets(availableCharsets):
Returns an array of preferred charsets ordered by priority from a list of available charsets.
##### charset(availableCharsets):
Returns the top preferred charset from a list of available charsets.
### Accept-Encoding Negotiation
```js
availableEncodings = ['identity', 'gzip']
negotiator = new Negotiator(request)
// Let's say Accept-Encoding header is 'gzip, compress;q=0.2, identity;q=0.5'
negotiator.encodings()
// -> ['gzip', 'identity', 'compress']
negotiator.encodings(availableEncodings)
// -> ['gzip', 'identity']
negotiator.encoding(availableEncodings)
// -> 'gzip'
```
You can check a working example at `examples/encoding.js`.
#### Methods
##### encodings(availableEncodings):
Returns an array of preferred encodings ordered by priority from a list of available encodings.
##### encoding(availableEncodings):
Returns the top preferred encoding from a list of available encodings.
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/negotiator.svg?style=flat
[npm-url]: https://npmjs.org/package/negotiator
[node-version-image]: https://img.shields.io/node/v/negotiator.svg?style=flat
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/negotiator.svg?style=flat
[travis-url]: https://travis-ci.org/jshttp/negotiator
[coveralls-image]: https://img.shields.io/coveralls/jshttp/negotiator.svg?style=flat
[coveralls-url]: https://coveralls.io/r/jshttp/negotiator?branch=master
[downloads-image]: https://img.shields.io/npm/dm/negotiator.svg?style=flat
[downloads-url]: https://npmjs.org/package/negotiator
{
"name": "negotiator",
"description": "HTTP content negotiation",
"version": "0.4.9",
"author": {
"name": "Federico Romero",
"email": "federico.romero@outboxlabs.com"
},
"contributors": [
{
"name": "Isaac Z. Schlueter",
"email": "i@izs.me",
"url": "http://blog.izs.me/"
}
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/negotiator"
},
"keywords": [
"http",
"content negotiation",
"accept",
"accept-language",
"accept-encoding",
"accept-charset"
],
"license": "MIT",
"devDependencies": {
"istanbul": "~0.3.2",
"nodeunit": "0.8.x"
},
"scripts": {
"test": "nodeunit test",
"test-cov": "istanbul cover ./node_modules/nodeunit/bin/nodeunit test"
},
"engines": {
"node": ">= 0.6"
},
"main": "lib/negotiator.js",
"files": [
"lib",
"LICENSE"
],
"gitHead": "1e90abd710b662db80f1ea244e647cce3bd74504",
"bugs": {
"url": "https://github.com/jshttp/negotiator/issues"
},
"homepage": "https://github.com/jshttp/negotiator",
"_id": "negotiator@0.4.9",
"_shasum": "92e46b6db53c7e421ed64a2bc94f08be7630df3f",
"_from": "negotiator@0.4.9",
"_npmVersion": "1.4.21",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "federomero",
"email": "federomero@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
}
],
"dist": {
"shasum": "92e46b6db53c7e421ed64a2bc94f08be7630df3f",
"tarball": "http://registry.npmjs.org/negotiator/-/negotiator-0.4.9.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.9.tgz",
"readme": "ERROR: No README data found!"
}
{
"name": "accepts",
"description": "Higher-level content negotiation",
"version": "1.1.4",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/jshttp/accepts"
},
"dependencies": {
"mime-types": "~2.0.4",
"negotiator": "0.4.9"
},
"devDependencies": {
"istanbul": "~0.3.4",
"mocha": "~2.0.1"
},
"files": [
"LICENSE",
"HISTORY.md",
"index.js"
],
"engines": {
"node": ">= 0.8"
},
"scripts": {
"test": "mocha --reporter spec --check-leaks --bail test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
},
"keywords": [
"content",
"negotiation",
"accept",
"accepts"
],
"gitHead": "df66414d80f096627b28f137127fce0a851d7900",
"bugs": {
"url": "https://github.com/jshttp/accepts/issues"
},
"homepage": "https://github.com/jshttp/accepts",
"_id": "accepts@1.1.4",
"_shasum": "d71c96f7d41d0feda2c38cd14e8a27c04158df4a",
"_from": "accepts@~1.1.4",
"_npmVersion": "1.4.21",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "federomero",
"email": "federomero@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "shtylman",
"email": "shtylman@gmail.com"
},
{
"name": "mscdex",
"email": "mscdex@mscdex.net"
},
{
"name": "fishrock123",
"email": "fishrock123@rocketmail.com"
}
],
"dist": {
"shasum": "d71c96f7d41d0feda2c38cd14e8a27c04158df4a",
"tarball": "http://registry.npmjs.org/accepts/-/accepts-1.1.4.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/accepts/-/accepts-1.1.4.tgz",
"readme": "ERROR: No README data found!"
}
0.5.0 / 2014-10-11
==================
* Add `parse` function
0.4.0 / 2014-09-21
==================
* Expand non-Unicode `filename` to the full ISO-8859-1 charset
0.3.0 / 2014-09-20
==================
* Add `fallback` option
* Add `type` option
0.2.0 / 2014-09-19
==================
* Reduce ambiguity of file names with hex escape in buggy browsers
0.1.2 / 2014-09-19
==================
* Fix periodic invalid Unicode filename header
0.1.1 / 2014-09-19
==================
* Fix invalid characters appearing in `filename*` parameter
0.1.0 / 2014-09-18
==================
* Make the `filename` argument optional
0.0.0 / 2014-09-18
==================
* Initial release
(The MIT License)
Copyright (c) 2014 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# content-disposition
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Create and parse HTTP `Content-Disposition` header
## Installation
```sh
$ npm install content-disposition
```
## API
```js
var contentDisposition = require('content-disposition')
```
### contentDisposition(filename, options)
Create an attachment `Content-Disposition` header value using the given file name,
if supplied. The `filename` is optional and if no file name is desired, but you
want to specify `options`, set `filename` to `undefined`.
```js
res.setHeader('Content-Disposition', contentDisposition('∫ maths.pdf'))
```
**note** HTTP headers are of the ISO-8859-1 character set. If you are writing this
header through a means different from `setHeader` in Node.js, you'll want to specify
the `'binary'` encoding in Node.js.
#### Options
`contentDisposition` accepts these properties in the options object.
##### fallback
If the `filename` option is outside ISO-8859-1, then the file name is actually
stored in a supplemental field for clients that support Unicode file names and
a ISO-8859-1 version of the file name is automatically generated.
This specifies the ISO-8859-1 file name to override the automatic generation or
disables the generation all together, defaults to `true`.
- A string will specify the ISO-8859-1 file name to use in place of automatic
generation.
- `false` will disable including a ISO-8859-1 file name and only include the
Unicode version (unless the file name is already ISO-8859-1).
- `true` will enable automatic generation if the file name is outside ISO-8859-1.
If the `filename` option is ISO-8859-1 and this option is specified and has a
different value, then the `filename` option is encoded in the extended field
and this set as the fallback field, even though they are both ISO-8859-1.
##### type
Specifies the disposition type, defaults to `"attachment"`. This can also be
`"inline"`, or any other value (all values except inline are treated like
`attachment`, but can convey additional information if both parties agree to
it). The type is normalized to lower-case.
### contentDisposition.parse(string)
```js
var disposition = contentDisposition.parse('attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt"');
```
Parse a `Content-Disposition` header string. This automatically handles extended
("Unicode") parameters by decoding them and providing them under the standard
parameter name. This will return an object with the following properties (examples
are shown for the string `'attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt'`):
- `type`: The disposition type (always lower case). Example: `'attachment'`
- `parameters`: An object of the parameters in the disposition (name of parameter
always lower case and extended versions replace non-extended versions). Example:
`{filename: "€ rates.txt"}`
## Examples
### Send a file for download
```js
var contentDisposition = require('content-disposition')
var destroy = require('destroy')
var http = require('http')
var onFinished = require('on-finished')
var filePath = '/path/to/public/plans.pdf'
http.createServer(function onRequest(req, res) {
// set headers
res.setHeader('Content-Type', 'application/pdf')
res.setHeader('Content-Disposition', contentDisposition(filePath))
// send file
var stream = fs.createReadStream(filePath)
stream.pipe(res)
onFinished(res, function (err) {
destroy(stream)
})
})
```
## Testing
```sh
$ npm test
```
## References
- [RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1][rfc-2616]
- [RFC 5987: Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters][rfc-5987]
- [RFC 6266: Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)][rfc-6266]
- [Test Cases for HTTP Content-Disposition header field (RFC 6266) and the Encodings defined in RFCs 2047, 2231 and 5987][tc-2231]
[rfc-2616]: https://tools.ietf.org/html/rfc2616
[rfc-5987]: https://tools.ietf.org/html/rfc5987
[rfc-6266]: https://tools.ietf.org/html/rfc6266
[tc-2231]: http://greenbytes.de/tech/tc2231/
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/content-disposition.svg?style=flat
[npm-url]: https://npmjs.org/package/content-disposition
[node-version-image]: https://img.shields.io/node/v/content-disposition.svg?style=flat
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/content-disposition.svg?style=flat
[travis-url]: https://travis-ci.org/jshttp/content-disposition
[coveralls-image]: https://img.shields.io/coveralls/jshttp/content-disposition.svg?style=flat
[coveralls-url]: https://coveralls.io/r/jshttp/content-disposition?branch=master
[downloads-image]: https://img.shields.io/npm/dm/content-disposition.svg?style=flat
[downloads-url]: https://npmjs.org/package/content-disposition
{
"name": "content-disposition",
"description": "Create and parse Content-Disposition header",
"version": "0.5.0",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
}
],
"license": "MIT",
"keywords": [
"content-disposition",
"http",
"rfc6266",
"res"
],
"repository": {
"type": "git",
"url": "https://github.com/jshttp/content-disposition"
},
"devDependencies": {
"istanbul": "0.3.2",
"mocha": "~1.21.4"
},
"files": [
"LICENSE",
"HISTORY.md",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
},
"gitHead": "f3c915f0c9d9f5ec79713dba24c8c6181b73305d",
"bugs": {
"url": "https://github.com/jshttp/content-disposition/issues"
},
"homepage": "https://github.com/jshttp/content-disposition",
"_id": "content-disposition@0.5.0",
"_shasum": "4284fe6ae0630874639e44e80a418c2934135e9e",
"_from": "content-disposition@0.5.0",
"_npmVersion": "1.4.21",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
}
],
"dist": {
"shasum": "4284fe6ae0630874639e44e80a418c2934135e9e",
"tarball": "http://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz",
"readme": "ERROR: No README data found!"
}
1.0.4 / 2014-06-25
==================
* corrected avoidance of timing attacks (thanks @tenbits!)
1.0.3 / 2014-01-28
==================
* [incorrect] fix for timing attacks
1.0.2 / 2014-01-28
==================
* fix missing repository warning
* fix typo in test
1.0.1 / 2013-04-15
==================
* Revert "Changed underlying HMAC algo. to sha512."
* Revert "Fix for timing attacks on MAC verification."
0.0.1 / 2010-01-03
==================
* Initial release
test:
@./node_modules/.bin/mocha \
--require should \
--reporter spec
.PHONY: test
\ No newline at end of file
# cookie-signature
Sign and unsign cookies.
## Example
```js
var cookie = require('cookie-signature');
var val = cookie.sign('hello', 'tobiiscool');
val.should.equal('hello.DGDUkGlIkCzPz+C0B064FNgHdEjox7ch8tOBGslZ5QI');
var val = cookie.sign('hello', 'tobiiscool');
cookie.unsign(val, 'tobiiscool').should.equal('hello');
cookie.unsign(val, 'luna').should.be.false;
```
## License
(The MIT License)
Copyright (c) 2012 LearnBoost &lt;tj@learnboost.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
// MIT License
Copyright (C) Roman Shtylman <shtylman@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"name": "debug",
"repo": "visionmedia/debug",
"description": "small debugging utility",
"version": "2.1.1",
"keywords": [
"debug",
"log",
"debugger"
],
"main": "browser.js",
"scripts": [
"browser.js",
"debug.js"
],
"dependencies": {
"guille/ms.js": "0.6.1"
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment